﻿WEBVTT

00:00:00.-485 --> 00:00:05.515
Translated by visionNoob, KNU
https://github.com/insurgent92/CS231N_17_KOR_SUB

00:00:08.355 --> 00:00:11.357
자 12시가 지났군요 시작합니다.

00:00:14.644 --> 00:00:17.419
우선 지난시간에 배운 내용을 복습하겠습니다.

00:00:17.419 --> 00:00:23.400
지난시간에 Nerural networks를 학습 시킬 때 필요한 여러가지
중요한 것들을 배웠습니다.

00:00:23.400 --> 00:00:30.439
지난 시간에 배운 내용을 다시 한번 살펴 본 뒤에
몇 가지 더 배워보겠습니다.

00:00:30.439 --> 00:00:34.707
우선 공지사항을 몇 가지 전달합니다.

00:00:34.707 --> 00:00:39.645
우선 과제 1의 마감기한이 종료되었습니다.
여러분 모두 잘 제출했길 바랍니다.

00:00:39.645 --> 00:00:57.322
다들 잘 했나요?
과제 1은 체점 중에 있습니다.

00:00:57.322 --> 00:01:04.121
그리고 두 번째는 프로젝트 제안서 제출은
금일 11:59 PM 까지 입니다.

00:01:04.959 --> 00:01:09.074
오늘 까지 꼭 제출 해 주시기 바랍니다.
자세한 사항은 web과 Piazza에서 확인바랍니다.

00:01:09.074 --> 00:01:15.269
그리고 과제 2가 나왔습니다.
제출까지 1주일정도의 기간이 남았습니다.

00:01:15.269 --> 00:01:25.860
과제 2는 우리 수업에서 가장 오래 걸리는 과제 입니다.
그러니 서둘러 진행 하는 것을 추천드립니다.

00:01:27.122 --> 00:01:32.484
그리고 과제 2를 하실때 팁을 드리자면
현재 대다수가 Googld Cloud를 쓰고 계신데

00:01:32.484 --> 00:01:38.586
Googld Cloud에서 instances를 사용하지 않을 시에는
반드시 종료시켜 줘야 합니다. 아니면 요금이 계속 지불됩니다.

00:01:38.586 --> 00:01:42.899
여러분들이 쿠폰을 너무 많이 씁니다.

00:01:42.899 --> 00:01:52.223
instance에서 아무 작업도 하지 않더라도 켜져 있으면
요금이 부과됩니다.

00:01:52.223 --> 00:01:57.118
그러니 사용하지 않으면 반드시 종료시켜 줘야 합니다.

00:01:57.118 --> 00:02:04.970
여기 제 대쉬보드 화면인데, 이런 식으로 확실하게
STOP 버튼을 눌러줘야 합니다.

00:02:04.970 --> 00:02:08.644
매일 매일 이렇게 종료 시켜 주시기 바랍니다.

00:02:09.481 --> 00:02:20.853
그리고 Googld Cloud를 사용할 때 아셔하 할 것은
GPU를 쓰는 것이 CPU보다 더 비싸다는 것입니다.

00:02:20.853 --> 00:02:28.322
GPU를 쓰시면 어림잡아 시간당 거의 1 달러를 사용하게 됩니다.
상당히 가격이 높습니다.

00:02:28.322 --> 00:02:39.739
CPU instances는 조금 더 쌉니다. 추천 드리는 방법은 GPU
instance는 GPU가 필요할 때만 쓰는 것입니다.

00:02:39.739 --> 00:02:47.377
가령 과제 2를 하실 때 대게는 CPU만 있으면 됩니다. 따라서
CPU instance만 사용하면 됩니다.

00:02:47.377 --> 00:02:52.990
 하지만 과제2의 마지막 문제를 풀때 사용하는
Tensorflow와 PyTorch는 GPU가 필요합니다.

00:02:52.990 --> 00:02:58.897
CPU와 GPU instance를 각각 만들고 정말 필요할 때만
GPU instance를 사용하시길 권장드립니다.

00:02:58.897 --> 00:03:04.307
그러니 비용이 얼마나 지불되는 지를 모니터링 하면서
지나치게 지불되는 것을 주의하시기 바랍니다.

00:03:04.307 --> 00:03:07.748
공지사항 관련한 질문사항 있나요?

00:03:11.180 --> 00:03:12.182
질문있나요?

00:03:12.182 --> 00:03:13.902
[학생이 질문]

00:03:13.902 --> 00:03:16.133
RAM을 얼마나 사용해야 하냐고 하셨는데

00:03:16.133 --> 00:03:21.863
과제용으로는 8~16기가면 충분합니다.

00:03:21.863 --> 00:03:27.114
CPU나 RAM을 너무 많이 추가하면 돈이 많이 듭니다.

00:03:27.114 --> 00:03:34.542
CPU는 2~4개를 쓰고 RAM은 8~16 기가를 쓰시면
과제 하실 때 충분한 사양입니다.

00:03:36.636 --> 00:03:40.417
지난 시간 내용을 복습해 보면
Activation function을 배웠습니다.

00:03:40.417 --> 00:03:44.962
지난 시간에 다양한 Activation Function과 각각의
특성을 배웠습니다.

00:03:44.962 --> 00:03:59.736
10년 전에는 sigmoid가 아주 유명했습니다. 하지만 Vanishing
gradients가 생기는 문제가 있었죠 tanh도 마찬가지 이구요

00:03:59.736 --> 00:04:09.230
그래서 요즘은 대부분 ReLU를 씁니다. 일반적인
네트워크에서 가장 잘 동작하는 녀석입니다.

00:04:09.230 --> 00:04:16.820
그래서 가중치 초기화에 대해서도 배웠습니다.

00:04:16.820 --> 00:04:23.787
가중치가 지나치게 작으면 activatiom이 사라집니다.

00:04:23.788 --> 00:04:29.583
작은 값이 여러 번 곱해지기 때문에 점점
0이 되는 것이었습니다.

00:04:29.583 --> 00:04:33.072
결국 모든 값이 0이 되고 학습은 일어나지 않습니다.

00:04:33.072 --> 00:04:41.208
반면에 가중치가 너무 큰 값으로 초기화되면 그 값이 또
계속 곱해질 것이고 결국은 터져버릴 것입니다(explode).

00:04:41.208 --> 00:04:45.389
이 경우에도 학습이 일어나지 않을 것입니다.

00:04:45.389 --> 00:04:58.531
Xavier/MSRA(HE) Initialzation 같은 방법으로 초기화를
잘 시켜주면 Activation의 분포를 좋게 유지시킬 수 있습니다.

00:04:58.531 --> 00:05:04.328
명심해야 할 점은 위의 것들이 Network가 깊어지면 깊어질
수록 더 중요하다는 것입니다.

00:05:04.328 --> 00:05:11.620
Network가 깊어지면 깊어질수록 가중치를 더 많이
곱하게 되기 때문입니다.

00:05:11.620 --> 00:05:23.666
그리고 데이터 전처리가 있었죠. CNN은 zero-mean을 주로 사용하며,
그 밖에 zero-mean, unit variance에 대해서도 배웠습니다.

00:05:23.666 --> 00:05:29.968
제가 여러분에게 왜 그걸 해야하는 지를 좀
더 직관적으로 말씀 드리겠습니다.

00:05:29.968 --> 00:05:39.532
자 여기에서 우리는 Binary classification 문제를 풉니다.
빨간/파란 점들을 나누는 것입니다.

00:05:39.532 --> 00:05:46.948
왼쪽의 경우 not normalized/centered 데이터 입니다.

00:05:46.948 --> 00:05:55.007
이 경우에도 물론 classification이 가능하지만 선이 조금만
움직여도 classification이 잘 되지 않습니다.

00:05:55.007 --> 00:06:05.992
왼쪽의 예시가 의미하는 것은 손실 함수가 아주 약간의
가중치 변화에도 엄청 예민하다는 것입니다.

00:06:07.315 --> 00:06:14.554
왼쪽의 경우 동일한 함수를 쓰더라도 학습 시키기 아주 어렵습니다.
재차 말씀드리지만 Loss가 파라미터에 너무 민감하기 때문입니다.

00:06:14.554 --> 00:06:25.351
반면 오른쪽은 데이터의 중심을 원점에 맞추고(zero-center),
Unit variance로 만들어 준 경우 입니다.

00:06:25.351 --> 00:06:35.523
오른쪽에서의 선이 조금씩 흔들리는 경우는 보면
손실 함수는 이런 가중치의 변동에 덜 민감함을 알 수 있습니다.

00:06:35.523 --> 00:06:41.064
이 경우가 최적화가 더 쉽습니다.
학습이 더 잘되는 것입니다.

00:06:41.064 --> 00:06:46.539
그리고 이는 Linear classification의 경우에만
국한되는 것이 아닙니다.

00:06:46.539 --> 00:06:57.756
Neural network 내부에도 다수의(interleavings)
linear classifer가 있다고 생각할 수 있습니다.

00:06:59.078 --> 00:07:05.687
이 경우에도 Neural network의 입력이 zero-centered가
아니고 Unit variance가 아닌 경우라면

00:07:05.687 --> 00:07:15.632
레이어의 Weight matrix가 아주 조금만 변해도 출력은 엄청
심하게 변하게 됩니다.  이는 학습을 어렵게 합니다.

00:07:15.632 --> 00:07:20.481
이를 통해 왜 nomalization가 중요한지를 좀 더
직관적으로 이해하실 수 있을 것입니다.

00:07:21.864 --> 00:07:26.862
자 우리는 Normalization이 엄청 중요하다는 것을 알고
있기 때문에 batch normalization도 배웠습니다.

00:07:26.862 --> 00:07:36.030
이는 actications이 zero mean과 unit variance가
될 수 있도록 레이어를 하나 추가하는 방법이었습니다.

00:07:36.030 --> 00:07:41.465
제가 이 슬라이드에 batch normalization 수식을
다시한번 적어 봤습니다.

00:07:41.465 --> 00:07:45.172
이 슬라이드를 보면 과제 2를 하실 때 수월할 것입니다.

00:07:45.172 --> 00:07:59.254
BN에서는 forward pass 시에 미니배치에서의 평균과 표준편차를
계산해서 Normalization을 수행했습니다.

00:07:59.254 --> 00:08:05.641
그리고 레이어의 유연한 표현성(expressivity)을 위해서
scale, shift 파라미터를 추가했습니다.

00:08:05.641 --> 00:08:09.990
과제 2를 하실때 이를 참고하시기 바랍니다.

00:08:09.990 --> 00:08:18.146
그리고 학습 과정을 다루는 방법도 배웠습니다. 학습 도중
Loss curve가 어떻게 보여야 하는지도 말이죠

00:08:18.146 --> 00:08:26.683
여기 예제 네트워크가 있습니다. 주말동안 한번 돌려봤습니다.
저는 학습을 진행할 때 이런 식으로 진행합니다.

00:08:26.683 --> 00:08:35.795
가운데 그래프는 시간에 따른 Loss 값을 나타냅니다.
네트워크가 Loss를 줄이고 있으면 잘 하고 있는 것이죠

00:08:35.795 --> 00:08:48.464
맨 오른쪽 그래프를 보면 X는 시간축이고 Y는 성능 지표입니다.
Training/Validation set의 성능지표를 나타냅니다.

00:08:48.465 --> 00:08:58.680
이를 해석해보면 Training set의 성능을 계속 올라가죠 Loss도
계속 내려갑니다. 하지만 validation은 침체하고 있습니다.

00:08:58.680 --> 00:09:05.066
이런 경우는 overfititing이라고 할 수 있겠습니다.
추가적인 regularization이 필요한 것입니다.

00:09:06.317 --> 00:09:09.504
그리고 이전 강의에서 hyperparameter search도 배웠습니다.

00:09:09.504 --> 00:09:14.798
네트워크에는 무수히 많은 하이퍼파라미터가 존재합니다.
이를 올바르게 잘 선택하는 것은 상당히 중요합니다.

00:09:14.798 --> 00:09:20.725
그리고 grid search와 random search를 배웠습니다.
이론상 random search가 더 좋았습니다.

00:09:20.725 --> 00:09:30.669
왜냐하면 성능이 특정 하이퍼파라미터에 의해 크게 좌우될 때 그
파라미터를 좀 더 넓은 범위로 탐색할 수 있기 때문입니다.

00:09:30.669 --> 00:09:37.005
그리고 하이퍼파라미터 최적화 시에
coarse search 이후 fine search를 한다고 배웠습니다.

00:09:37.005 --> 00:09:43.408
처음에는 하이퍼파라미터를 조금 더 넒은 범위에서 찾습니다.
Interation도 작게 줘서 학습시켜봅니다.(coarse)

00:09:43.408 --> 00:09:47.973
그리고 결과가 좋은 범위로 좁히는 것입니다.

00:09:47.973 --> 00:09:51.666
그리고 iterations를 조금 더 돌면서 더 작은 범위를
다시 탐색합니다. (fine search)

00:09:51.666 --> 00:09:56.708
적절한 하이퍼파라미터를 찾을 때 까지
이 과정을 반복합니다.

00:09:56.708 --> 00:10:04.455
가장 중요한 점은 coarse range를 설정할 때 가능한
최대한 넓은 범위를 설정해 줘야 한다는 것입니다.

00:10:04.455 --> 00:10:13.746
그 범위가 하이퍼파라미터 범위의 끝에서 끝까지 다 살펴볼 수
있도록 할수록 좋습니다. 충분히 넓은 범위를 사용해야 합니다.

00:10:17.462 --> 00:10:18.295
질문 있나요?

00:10:20.044 --> 00:10:26.672
[학생이 질문]

00:10:31.840 --> 00:10:34.554
질문은 보통 하이퍼파라미터를 몇 개씩 선택하는지 입니다.

00:10:34.554 --> 00:10:38.244
여기 예제에서는 2개 인데 보통은 2개보단 많습니다.

00:10:38.244 --> 00:10:45.442
그 선택은 모델에 따라 다릅니다. 선택한 하이퍼파라미터의 수가
많을 수록 기하급수적으로 경우의 수가 늘어납니다.

00:10:45.442 --> 00:10:48.012
때문에 한번에 너무 많이 할 수 는 없습니다.

00:10:48.012 --> 00:10:51.737
또 이는 여러분이 얼마나 많은 자원을
학습에 사용할 수 있는지도 중요합니다.

00:10:51.737 --> 00:10:55.745
이는 사람마다 다르고 실험마다 다릅니다.

00:10:55.745 --> 00:11:05.353
저같은 경우 두 세가지 정도를 고르는 편이고 많아도 네 가지 정도만
선택합니다. 그 이상이면 out of control이 되버립니다.

00:11:05.353 --> 00:11:10.406
일반적으로는 Learning rate가 가장 중요합니다.
Learning rate를 가장 먼저 선택해 놔야만 합니다.

00:11:10.406 --> 00:11:19.542
regularization, learning rate decay,
model size 같은 것들은 LR보단 덜 중요합니다.

00:11:19.542 --> 00:11:22.723
Block Coordinate Descent(BCD)
같은 방법을 쓸 수도 있습니다.

00:11:22.723 --> 00:11:27.459
가령, 우선 Learning rate를 정해놓은 다음에 다양한
모델 사이즈를 시도해 보는 것입니다.

00:11:27.459 --> 00:11:30.759
이 방법을 쓰면 기하급수적으로 늘어나는 Search space를
조금은 줄일 수 있습니다.

00:11:30.759 --> 00:11:35.370
하지만 이 방법은 정확히 어떤 순서로 어떻게 찾아야
할지 정해야 하는 것이 가장 큰 문제입니다.

00:11:36.253 --> 00:11:38.120
다른 질문 있으신가요?

00:11:38.120 --> 00:11:57.041
[학생이 질문]

00:11:57.041 --> 00:12:04.537
질문은 우리가 어떤 하이퍼파리미터 값을 변경할 시에 다른 하이퍼파라미터
의 최적 값이 변해버리는 경우가 빈번하냐는 것입니다.

00:12:04.537 --> 00:12:11.339
그런 일이 가끔 발생하긴 합니다.  Learning rates가 이런 문제에
덜 민감함에도 실제로 이런 일이 발생하곤 합니다.

00:12:11.339 --> 00:12:18.130
Leraning rates가 좋은 범위 내에 속했으면 하지만 보통은
optimal 보다는 작은 값이고 학습 속도가 길어지곤 합니다.

00:12:18.130 --> 00:12:31.291
이런 경우에는, 오늘 배우게 될, 더 좋은(fancier) 최적화 방법을
사용하면 모델이 learning rate에 덜 민감하도록 할 수 있습니다.

00:12:31.291 --> 00:12:32.962
다른 질문 있으신가요?

00:12:32.962 --> 00:12:37.308
[학생이 질문]

00:12:37.308 --> 00:12:41.292
질문은 Learning rate를 작게 하고 Epoch을 늘리면
어떤 일이 발생하는지 입니다.

00:12:41.292 --> 00:12:45.139
그렇게 되면 엄청 오래 걸리겠죠

00:12:45.139 --> 00:12:48.383
[학생이 질문]

00:12:48.383 --> 00:12:54.853
Learning rates를 낮추고 오랫동안 학습시키게 되면
이론적으로는 항상 동작하는 것이 맞습니다.

00:12:54.853 --> 00:13:00.491
하지만 실제로는 Learning rate가 0.01이냐 0.001이냐는
상당히 중요한 문제가 됩니다.

00:13:00.491 --> 00:13:03.931
여러분이 적절한 Leraning rate를 찾으면 6시간, 12시간 또는
하루면 학습을 다 시킬 수 있을 텐데

00:13:03.931 --> 00:13:11.911
 그런데 여러분이 엄청 조심스러워서 Learning rate를
10배, 100배 줄여 버라면 하루면 끝나는 것이 100일이 걸릴수 있습니다.

00:13:11.911 --> 00:13:16.400
그럼 세 달이 걸리게 되는 것입니다. 좋지 않은 경우입니다.

00:13:16.400 --> 00:13:20.668
보통 컴퓨터과학 분야를 배울때 이런 constants(10배 100배)를
중요하게 다루지 않는 경향이 있는데

00:13:20.668 --> 00:13:25.444
당신은 실제로 훈련하는 것에 대해 생각하고 있습니다.
그 constants은 많은 문제가됩니다.

00:13:25.444 --> 00:13:26.861
다른 질문 있나요?

00:13:27.877 --> 00:13:33.385
[학생이 질문]

00:13:33.385 --> 00:13:37.807
질문은 Low learning rate를 주게되면
local optima에 빠질 수 있지 않냐는 것입니다.

00:13:37.807 --> 00:13:42.601
이는 직관적으로는 그럴 수 있겠지만 실제로
그런 일은 많이 발생하지는 않습니다.

00:13:42.601 --> 00:13:47.030
이에 관한 내용을 오늘 잠시 뒤에 다시 배울 것입니다.

00:13:47.030 --> 00:13:53.151
오늘은 Neural networks를 학습시킬 때 필요한 흥미롭고
아주 중요한 문제를 몇 가지 배워보도록 하겠습니다.

00:13:53.151 --> 00:13:59.655
제가 이전에 더 강력한 최적화 알고리즘이 있다고
앞서 몇 번 언급한 적이 있었습니다.

00:13:59.655 --> 00:14:07.067
오늘은 사람들이 많이 사용하는 그 강력한 알고리즘들에 대해서
좀 더 자세히 알아보는 시간이 되겠습니다.

00:14:07.067 --> 00:14:10.364
지난 강의에 Regularization에 대해서도 조금 배웠었죠

00:14:10.364 --> 00:14:15.806
네트워크의 Train/Test Error 간의 격차를 줄이고자
사용하는 추가적인 기법입니다.

00:14:15.806 --> 00:14:22.143
Neural Network에서 실제로 사람들이 사용하고 있는
Regularization 전략에 대해서 다뤄보도록 하겠습니다.

00:14:22.143 --> 00:14:26.401
그리고 Transfer learning에 대해서도 배울 것입니다.

00:14:26.401 --> 00:14:31.490
원하는 양 보다 더 적은 데이터만을 가지고 있을때
사용할 수 있는 방법입니다.

00:14:32.821 --> 00:14:39.885
지난 강의를 돌이켜보면 Neural network에서 가장 중요한 것은
바로 최적화 문제 였다는 것을 알 수 있습니다.

00:14:39.885 --> 00:14:50.982
Nerwork의 가중치에 대해서 손실 함수를 정의해 놓으면 이
손심 함수는 그 가중치가 얼마나 좋은지 나쁜지를 알려줍니다.

00:14:50.982 --> 00:14:56.508
그리고 우리는 손심 함수가 가중치에 대한
"산(landscape)"이라고 상상해 볼 수 있을 것입니다.

00:14:56.508 --> 00:15:04.142
여기 맨 오른쪽 사진에 간단한 예제를 가져왔습니다.
X/Y축은 두 개의 가중치를 의미합니다.

00:15:04.142 --> 00:15:07.984
그리고 각 색은 Loss의 값을 나타냅니다.

00:15:07.984 --> 00:15:15.195
이 오른쪽의 2차원의 문제를  두 개의 가중치
W_1과 W_2를 최적화 시키는 문제라고 생각해 봅시다.

00:15:15.195 --> 00:15:23.203
우리의 목적은 가장 붉은색인 지점을 찾는 것입니다.
즉 가장 낮은 Loss를 가진 가중치를 찾는 것이죠.

00:15:23.203 --> 00:15:29.099
자 지금까지 배운 것을 생각해 봅시다. 가장 간단한 최적화 알고리즘은
바로 Stochastic Gradient Descent 입니다.

00:15:29.099 --> 00:15:32.393
이 세 줄로 된 엄청 간단한 알고리즘이죠

00:15:32.393 --> 00:15:39.179
우선 미니 배치 안의 데이터에서 Loss를 계산합니다.

00:15:39.179 --> 00:15:44.656
그리고 'Gradient 의 반대 방향" 을 이용해서
파라미터 벡터를 업데이트합니다.

00:15:44.656 --> 00:15:48.798
반대 방향인 이유는 손실 함수를 내려가는
방향 이어야 하기 때문입니다.

00:15:48.798 --> 00:15:56.282
이 단계를 계속 반복하면 결국 붉은색 지역으로 수렴할 것이고
Loss가 낮을 것입니다.

00:15:56.282 --> 00:16:05.462
하지만 이 심플한 알고리즘을 실제로 사용하게 되면
몇 가지 문제에 봉착하고 맙니다.

00:16:05.462 --> 00:16:08.713
SGD의 문제점 중 하나는,

00:16:08.713 --> 00:16:18.969
가령 우리의 손실함수가 이런 식으로 생겼다고 생각해 봅시다.
여기에 똑같이 W_1과 W_2가 있다고 해봅시다.

00:16:18.969 --> 00:16:23.472
둘중 어떤 하나는 업데이트를 해도 손실 함수가
아주 느리게 변합니다.

00:16:23.472 --> 00:16:26.687
즉, 수평 축의 가중치는 변해도 Loss가 아주 천천히 줄어듭니다.

00:16:28.152 --> 00:16:34.930
다시 말해 Loss는 수직 방향의 가중치 변화에 훨씬 더
민감하게 반응하는 것입니다.

00:16:34.930 --> 00:16:40.757
다시 말해 현재 지점에서 Loss는 bad condition number를
지니고 있다고 말할 수 있을 것입니다.

00:16:40.757 --> 00:16:46.050
이 지점의 Hessian maxrix의 최대/최소 singular values
값의 비율이 매우 안좋다는 뜻입니다.

00:16:46.050 --> 00:16:50.497
이를 좀 더 직관적으로 이해해보면 우선 Loss가
 taco shell 같은 모양입니다.

00:16:50.497 --> 00:16:54.393
한 방향으로는 엄청나게 민감한 반면에 다른 방향으로는
덜 민감한 상태에 있는 것입니다.

00:16:54.393 --> 00:17:00.633
그렇다면 질문입니다. 이런 상황에서 SGD으로 학습이 되는
과정은 어떤 모습일까요?

00:17:05.310 --> 00:17:12.196
손실 함수가 이런 식으로 생긴 환경에서 SGD를 수행하면,
이런 특이한 지그재그 형태를 볼 수 있을 것입니다.

00:17:12.197 --> 00:17:22.111
왜냐하면 이런 함수에서는 gradient의 방향이
고르지 못하기 때문입니다.

00:17:22.112 --> 00:17:29.335
Gradient를 계산하고 업데이트 하게 되면 line을
넘나들면서  왔다갔다 하게 됩니다.

00:17:29.335 --> 00:17:35.995
Loss에 영향을 덜 주는 수평방향 차원의 가중치는
업데이트가 아주 느리게 진행됩니다.

00:17:35.995 --> 00:17:41.551
이렇게 빠르게 변하는 수직 차원을 가로지르면서
지그지그로 아주 지저분하게(nasty) 움직이게 됩니다.

00:17:41.551 --> 00:17:50.139
아주 바람직하지 않은 행동입니다. 그리고 이 문제는 고차원
공간에서 훨씬 더 빈번하게 발생합니다.

00:17:51.186 --> 00:18:00.617
우리가 본 예시 그림은 2차원 밖에 되지 않습니다만 실제로는
가중치가 수천 수억개 일 수 있을 것입니다.

00:18:00.617 --> 00:18:14.221
이 경우 수억개의 방향으로 움직일 수 있습니다. 이런 수억개의 방향중에
불균형한 방향이 존재한다면 SGD는 잘 동작하지 않을 것입니다.

00:18:14.221 --> 00:18:20.573
수억개의 파라미터가 있다고 했을때 이런 불균형의
발생 비율은 상당히 높습니다.

00:18:20.573 --> 00:18:26.398
고차원 공간에서 발생할 수 있는 이런 문제는
실제로도 정말 큰 문제가 됩니다.

00:18:27.793 --> 00:18:33.564
SGD에서 발생하는 또 다른 문제는
local minima 와 saddle points와 관련된 문제입니다.

00:18:33.564 --> 00:18:44.003
그림을 좀 바꿨습니다. 이제는 X축은 어떤 하나의 가중치를 나타내고
Y축은 Loss를 나타내고 있습니다.

00:18:44.003 --> 00:18:51.583
우선 위의 그래프를 보면, 이 휘어진 손실함수는
중간에 "valley"가 하나 있습니다.

00:18:51.583 --> 00:18:55.036
이런 상황에서 SGD는 어떻게 움직일까요?

00:18:55.036 --> 00:18:57.031
[학생이 대답]

00:18:57.031 --> 00:19:04.454
이 경우 SGD는 멈춰버립니다. 왜냐하면 gradient가 0이
되기 때문이죠. locally falt 합니다.

00:19:04.454 --> 00:19:09.194
SGD의 동작을 생각해보면 gradient를 계산하고
그 반대방향으로 이동하는 것 이었습니다.

00:19:09.194 --> 00:19:15.862
저 위치에서는 "opposite gradient" 도 0 이 되며,
따라서 학습이 멈춰버리게 됩니다.

00:19:15.862 --> 00:19:19.406
또 다른 문제는 saddle points에 관한 것입니다.

00:19:19.406 --> 00:19:26.140
local minima는 아니지만, 한쪽 방향으로는 증가하고 있고
다른 한쪽 방향으로는 감소하고 있는 지역을 생각해 볼 수 있습니다.

00:19:26.140 --> 00:19:28.953
이런 곳에서도 gradient는 0이 됩니다.(아래 그림)

00:19:28.953 --> 00:19:35.899
saddle point에서도 gradient = 0 이므로 멈추게 됩니다.

00:19:35.899 --> 00:19:48.122
비록 이처럼 1차원의 예제만 봐서는 local minima가 엄청 심각하고
saddle point는 좀 덜 심각해 보이지만,

00:19:48.122 --> 00:19:57.171
고차원 공간에서는 그 반대입니다. 여러분에게 1억 차원의 공간이
있다고 생각해 봅시다. 여기에서 saddle point는 무엇일까요?

00:19:57.171 --> 00:20:03.135
Saddle point가 의미하는 것이 어떤 방향은 Loss가 증가하고
몇몇 방향은 Loss가 감소하고 있는 곳을 생각해 볼 수 있습니다.

00:20:03.135 --> 00:20:09.591
1억개의 차원에서 생각해보면 이는 정말 빈번하게 발생합니다.
사실 거의 모든 곳에서 발생한다고 할 수 있습니다.

00:20:09.591 --> 00:20:16.744
Local minima를 생각해보면 1억 개의 방향을 계산했는데 그 방향이
전부 Loss가 상승하는 방향이라는 것입니다.

00:20:16.744 --> 00:20:22.316
고차원 공간을 생각하면 그런 일이 발생하는 것은
매우 드문 경우입니다.

00:20:23.270 --> 00:20:33.283
지난 몇 년간 알려진 사실은 very large neural network가
local minima 보다는 saddle point에 취약하다는 것입니다.

00:20:33.283 --> 00:20:40.140
그리고 또한  saddle point 뿐만 아니라  saddle point의
근처에서도 문제는 발생합니다.

00:20:40.140 --> 00:20:47.935
아래 예시를 보면 saddle point 근처에서 gradient가 0 은
아니지만 기울기가 아주 작습니다.

00:20:47.935 --> 00:20:53.611
그것이 의미하는 바는 gradient를 계산해서 업데이트를 해도
기울기가 아주 작기 때문에

00:20:53.611 --> 00:21:01.872
현재 가중치의 위치가 saddle point 근처라면
업데이트는 아주 느리게 진행됩니다.

00:21:01.872 --> 00:21:10.115
이는 아주 큰 문제입니다.
그리고 SGD의 또 다른 문제가 있습니다.

00:21:10.115 --> 00:21:13.521
SGD는 Stochastic gradient descent라는
것을 다시한번 명심하시기 바랍니다.

00:21:13.521 --> 00:21:20.586
사실 손실함수를 계산할 때는 엄청 엄청 많은 Traing set
각각의  loss를 전부 계산해야 합니다.

00:21:20.586 --> 00:21:26.119
이 예시의 N이 전체 training set일 경우에
이 값은 "n = 백만"이 될 수도 있습니다.

00:21:26.119 --> 00:21:29.347
Loss를 계산할 때 마다 매번 전부를 계산하는 것은 어렵습니다.

00:21:29.347 --> 00:21:36.957
그래서 실제로는 미니배치의 데이터들만 가지고
실제 Loss를 추정하기만 합니다.

00:21:36.957 --> 00:21:42.148
이는 매번 정확한 gradient를 얻을 수가
없다는 것을 의미합니다.

00:21:42.148 --> 00:21:46.773
대신에 gradient의 부정확한
추정값(noisy estimate) 만을 구할 뿐입니다.

00:21:46.773 --> 00:21:50.575
오른쪽에 보이는 것은 제가 좀 과장해서 그린 것입니다.

00:21:50.575 --> 00:21:59.927
각 지점의 gradient에 random uniform noise를 추가하고
SGD를 수행하게 만들었습니다.

00:21:59.927 --> 00:22:07.987
따라서 실제로 SGD가 이런식으로 동작하진 않지만 이 예제로
gradient에 noise가 들어가면 어떻게 되는지 알 수 있습니다.

00:22:07.987 --> 00:22:14.036
손실함수 공간을 이런식으로 비틀거리면서 돌아다니게 되면
minima까지 도달하는데 시간이 더 오래 걸릴 것입니다.

00:22:15.723 --> 00:22:18.966
지금까지 SGD에 어떤 문제가 있는지에 대해서
이야기해 보았습니다.

00:22:18.966 --> 00:22:20.956
질문 있나요?

00:22:20.956 --> 00:22:25.123
[학생이 질문]

00:22:29.099 --> 00:22:34.435
질문은 바로 SGD를 쓰지 않고 그냥 GD를 쓰면
이런 문제가 전부 해결되는지 입니다.

00:22:35.281 --> 00:22:44.106
자 이전의 taco shell에서의 문제를 다시한번 살펴보면
full batch gradient descent에서도 같은 문제가 발생합니다

00:22:44.106 --> 00:22:54.120
Noise의 문제도 한번 볼까요. Noise는 미니배치이기 때문에서만이
아니라 네트워크의  explicit stochasticity 로도 발생합니다.

00:22:54.120 --> 00:22:57.736
이는 나중에 더 살펴 볼 것이지만
이는 여전히 문제가 됩니다.

00:22:57.736 --> 00:23:05.101
Saddle points 또한 full batch GD에서 문제가 됩니다.
전체 데이터를 사용한다고 해도 여전히 나타날 수 있겠죠

00:23:05.101 --> 00:23:10.249
기본적으로 full batch gradient descent를 사용한다
하더라도 이런 문제들이 해결되지는 않습니다.

00:23:10.249 --> 00:23:16.604
이러한 위험요소들을 다루기 위해서는 더 좋은
최적화 알고리즘이 필요합니다.

00:23:16.604 --> 00:23:21.966
이번 문제들의 대다수를 해결할 수 있는 아주
간단한 방법이 하나 있습니다.

00:23:21.966 --> 00:23:26.978
SGD에 momentum term을 추가하는 것이죠

00:23:26.978 --> 00:23:32.923
왼쪽은 classic 버전의 SGD입니다.
오로지 gradient 방향으로만 움직이는 녀석이죠

00:23:32.923 --> 00:23:43.062
반면 오른쪽은 SGD + momentum 입니다. 엄청 조금의 변화만
있습니다. 2개의 수식과 5라인의 코드를 보실 수 있죠

00:23:43.062 --> 00:23:51.331
아이디어는 아주 간단합니다. 그저 velocity를 유지하는 것입니다.
gradient 를 계산할 때 velocity를 이용합니다.

00:23:51.331 --> 00:23:57.811
현재 미니배치의 gradient 방향만 고려하는 것이 아니라
velocity를 같이 고려하는 것입니다.

00:23:57.811 --> 00:24:04.825
여기에는 하이퍼 파라미터 rho가 추가되었습니다.
momemtum의 비율을 나타냅니다.

00:24:05.925 --> 00:24:16.848
velocity의 영향력을 rho의 비율로 맞춰주는데
보통 0.9와 같은 높은 값으로 맞춰줍니다.

00:24:16.848 --> 00:24:21.173
velocity에 일정 비율 rho를 곱해주고
현재 gradient를 더합니다.

00:24:21.173 --> 00:24:26.999
이를 통해서 우리는 이제 gradient vector 그대로의 방향이 아닌
velocity vector의 방향으로 나아가게 됩니다.

00:24:28.327 --> 00:24:34.548
엄청 간단한 방법이지만 지금까지 말했던 문제들을
해결하는데 많은 도움을 줄 수 있습니다.

00:24:34.548 --> 00:24:44.809
local minima와 saddle points문제를 생각해보면 물리적으로
공이 굴러내려오는 것을 상상해 볼 수 있습니다.

00:24:44.809 --> 00:24:48.215
이 공은 떨어지면 속도가 점점 빨라집니다.

00:24:48.215 --> 00:24:56.922
이 공은 local minima에 도달해도 여전히 velocity를 가지고
있기 때문에 gradient = 0 이라도 움직일 수 있습니다.

00:24:56.922 --> 00:25:01.039
때문에 local minima를 극복할 수 있게 되고
계속해서 내려갈 수 있습니다.

00:25:01.039 --> 00:25:03.809
 saddle points에서도 비슷한 일이 일어나겠죠

00:25:03.809 --> 00:25:10.734
saddle point 주변의 gradient가 작더라도, 굴러내려오는 속도가
있기 때문에 velocity를 가지게 됩니다.

00:25:10.734 --> 00:25:16.462
때문에 saddle point를 잘 극복해 내고 계속
밑으로 내려올 수 있는 것입니다.

00:25:16.462 --> 00:25:21.949
업데이트가 잘 안되는 경우(poor conditioning) 를 다시
한번 살펴보겠습니다.

00:25:21.949 --> 00:25:31.105
아래와 같이 지그재그로 움직이는 상황이라면
momentum이 이 변동을 서로 상쇄시켜 버립니다.

00:25:31.105 --> 00:25:46.006
이를 통해서 loss에 만감한 수직 방향의 변동은 줄여주고
수평방향의 움직임은 점차 가속화 될 것입니다.

00:25:46.006 --> 00:25:51.344
momentum을 추가하게 되면 high condition number
problem을 해결하는 데 도움이 되는 것입니다.

00:25:51.344 --> 00:26:05.207
오른쪽을 보면 검은색이 일반 SGD입니다. 지그지그로 움직이죠.
파란색이 Momentum SGD입니다.

00:26:05.207 --> 00:26:12.644
Momentum을 추가해서 velocity가 생기면
결국 noise가 평균화되버립니다.

00:26:12.644 --> 00:26:20.337
보통의 SGD가 구불구불 움직이는 것에 비해서 momemum은
minima를 향해서 더 부드럽게 움직입니다.

00:26:20.337 --> 00:26:21.532
질문 있나요?

00:26:21.532 --> 00:26:25.699
[학생이 질문]

00:26:34.776 --> 00:26:40.465
문제는 어떻게 SGD Momemtum이 poorly conditioned
coordinate 문제를 해결할 수 있는지 입니다.

00:26:40.465 --> 00:26:49.125
우선 velocity estimation term에서 velocity가 어떻게
계산되는지를 보면 gradient를 계속해서 더해갑니다.

00:26:49.125 --> 00:26:56.603
이는 하이퍼파라미터인 rho에 영향을 받습니다.
그리고 현재 gradient가 상대적으로 작은 값이고

00:26:56.603 --> 00:26:59.254
그리고 이 상황에서 rho가 적절한 값으로
잘 동작한다고 하면

00:26:59.254 --> 00:27:05.512
그러면 velocity가 실제 gradient보다 더 커지는
지점 까지 조금씩 증가할 것입니다.

00:27:05.512 --> 00:27:10.377
이는  poorly conditioned dimension에서 더 빨리
학습될 수 있도록 도와줍니다.

00:27:12.569 --> 00:27:18.020
SGD momentum를 연상할 때 유용한 그림이 있습니다.

00:27:18.020 --> 00:27:20.273
빨간 점이 현재 지점입니다.

00:27:20.273 --> 00:27:30.075
Red Vector는 현재 지점에서의 gradient의 방향을 나타냅니다.
Green vector는 Velocity vector입니다.

00:27:30.075 --> 00:27:36.317
실제 업데이트는(autual step) 이 둘의 가중평균으로
구할 수 있습니다.

00:27:36.317 --> 00:27:40.049
이는 gradient의 noise를 극복할 수 있게 해줍니다.

00:27:40.049 --> 00:27:47.724
Momentum의 변형이 있습니다. Nesterov accelerated
gradient 인데, Nesterov momentum 라고도 합니다.

00:27:47.724 --> 00:27:51.737
계산하는 순서를 조금 바꾼 것입니다.

00:27:51.737 --> 00:28:00.285
기본 SGD momentum은 "현재 지점" 에서의 gradient를
계산한 뒤에 velocity와 섞어 줍니다.

00:28:00.285 --> 00:28:04.229
Nesterov를 사용하면 방법이 조금 다릅니다.

00:28:04.229 --> 00:28:10.765
빨간 점에서 시작해서 우선은 Velocity방향으로 움직입니다.

00:28:10.765 --> 00:28:18.732
그리고 그 지점에서의 gradient를 계산합니다. 그리고 다시
원점으로 돌아가서 둘을 합치는 것입니다.

00:28:18.732 --> 00:28:25.679
완벽한 설명은 아니지만 두 정보를 약간 더 섞어준다고
생각해 볼 수 있을 것입니다.

00:28:25.679 --> 00:28:34.702
velocity의 방향이 잘못되었을 경우에 현재 gradient의 방향을
좀 더 활용할 수 있도록 해줍니다.

00:28:34.702 --> 00:28:39.351
Nesterov는 Convex optimization 문제에서는
뛰어난 성능을 보이지만

00:28:39.351 --> 00:28:45.946
하지만 Neural network와 같은 non-convex problem
에서는 성능이 보장되지는 않습니다.

00:28:45.946 --> 00:28:51.061
Nesterov의 수식은 다음과 같습니다.

00:28:51.061 --> 00:28:57.155
velocity를 업데이트하기 위해서 이전의 velocity와
(x + pv)에서의 gradient를 계산합니다.

00:28:57.155 --> 00:29:06.222
그리고 step update는 앞서 계산한 velocity를
이용해서 구해줍니다.

00:29:06.222 --> 00:29:07.055
질문 있나요?

00:29:08.437 --> 00:29:12.357
[학생이 질문]

00:29:12.357 --> 00:29:14.743
질문은 velocity의 초기값을 구하는 좋은 방법이 있는지 입니다.

00:29:14.743 --> 00:29:16.998
velocity의 초기값은 항상 0입니다.

00:29:16.998 --> 00:29:20.096
이는 하이퍼파라미터가 아닙니다. 그저 0으로 둡니다.

00:29:20.096 --> 00:29:21.315
다른 질문 있나요?

00:29:21.315 --> 00:29:25.482
[학생이 질문]

00:29:31.992 --> 00:29:38.068
직관적으로 보면 velocity은 이전 gradients의
weighted sum입니다.

00:29:38.068 --> 00:29:41.466
[학생이 질문]

00:29:41.466 --> 00:29:44.027
그리고 더 최근의 gradients에 가중치가 더 크게 부여됩니다.

00:29:44.027 --> 00:29:49.716
매 스텝마다 이전 velocity에  rho(0.9 or 0.99) 를 곱하고
현재 gradient를 더해줍니다.

00:29:49.716 --> 00:29:54.662
그리고 이를 moving average라고 볼 수 있습니다.
(exponentially weighted moving average)

00:29:54.662 --> 00:30:00.109
그리고 시간이 지날수록 이전의 gradient들은
exponentially하게 감소합니다.

00:30:02.627 --> 00:30:11.632
Nesterov의 공식을 보시게 되면 다소 까다롭게 생겼습니다. 기존에는
Loss와 Gradient를 같은 점(x_t)에서 구했었습니다.

00:30:11.632 --> 00:30:19.283
Nesterov는 이 규칙을 조금 비틀어 버렸습니다. 이는 상당히 성가시지만
다행이도 쉽게 해결할 수 있는 변형 공식이 있습니다.

00:30:19.283 --> 00:30:29.392
변수들을 적절히 잘 바꿔주면 Nesterov를 조금 다르게 표현할 수 있으며
Loss와 Gradient를 같은 점에서 계산할 수 있게 됩니다.

00:30:29.392 --> 00:30:34.093
그리고 수정된 수식을 통해서 우리는 Nesterov를
새롭게 이해해 볼 수 있습니다.

00:30:34.093 --> 00:30:41.739
첫 번째 수식은 기존의 momentum과 동일합니다.

00:30:41.739 --> 00:30:48.178
기존과 동일하게 velocity 와 계산한 gradient를
일정 비율로 섞어주는 역할을 합니다.

00:30:48.178 --> 00:30:51.951
그리고 두 번째로 맨 밑의 수식을 보시기 바랍니다.

00:30:51.951 --> 00:30:57.592
우선 현재 점과 velocity를 더해줍니다.
여기 까지는 기존과 동일하죠

00:30:57.592 --> 00:31:01.454
그리고 여기에 "현재 velocity - 이전 velocity" 를 계산해서
일정 비율(rho)을 곱하고 더해줍니다.

00:31:01.454 --> 00:31:11.271
Nesterov momentum는 현재/이전의 velocity간의
에러보정(error-correcting term)이 추가됐습니다.

00:31:13.029 --> 00:31:25.249
SGD, Momentum, Nesterov의 예시를 한번 살펴봅시다.
기본 SGD은 검정색인데 세월아 네월아 내려가고 있습니다.

00:31:26.346 --> 00:31:29.598
파란색과 초록색이 momentum과 Nesterov입니다.

00:31:29.598 --> 00:31:36.803
momentum방법들은 minima를 그냥 지나쳐 버리는 경향이 있습니다.
이전의 velocity의 영향을 받기 때문입니다.

00:31:36.803 --> 00:31:39.849
하지만 스스로 경로를 수정하고는 결국 minima에 수렴합니다.

00:31:39.849 --> 00:31:40.682
질문 있나요?

00:31:42.023 --> 00:31:46.190
[학생이 질문]

00:31:52.024 --> 00:31:58.050
질문은 이 예시만 보면 momentum이 엄청 좋아 보이는데 만일
minima가 엄청 좁고 깊은 곳이라면 어떻게 되는지 입니다.

00:31:58.050 --> 00:32:01.527
momentum의 velocity가 오히려 minima를 건너 뛰는
현상도 발생할 수 있지 않을까요?

00:32:01.527 --> 00:32:05.232
그 부분은 상당히 흥미롭습니다. 그리고 이에 관련한
최근의 연구들이 주목하는 주제이기도 합니다.

00:32:05.232 --> 00:32:09.071
하지만 사실은 그렇게 좁고 깊은(sharp) minima는
좋은 minima가 아닙니다.

00:32:09.071 --> 00:32:17.601
그리고 사실 우리는 그런 곳에 도달하는 것도 원하지 않습니다.
좁고 깊은 minima는 훨씬 더 심한 overfits을 불러오게 됩니다.

00:32:17.601 --> 00:32:22.026
가령 Training set을 두배 늘어났다고 생각해보면, 최적화 시키는
산의 지형(landscape)자체가 바뀌게 될 것입니다.

00:32:22.026 --> 00:32:27.420
Training data이 더 많이 모이면 그런
민감한 minima는 점점 사라집니다.

00:32:27.420 --> 00:32:31.189
여기에서 얻을 수 있는 직관은 우리가 원하는 minima는
아주 평평한 minima 라는 것입니다.

00:32:31.189 --> 00:32:35.933
왜냐하면 "아주 평평한 minima"는 Training data의 변화에
좀 더 강인할 지도 모르기 때문입니다.

00:32:35.933 --> 00:32:40.453
결국 평평한 minima가 더 일반화를 잘 할 수도 있으며,
 Testing data에도 더 좋은 결과를 얻을 수 있을 것입니다.

00:32:40.453 --> 00:32:46.284
다시한번 말씀드리지만 이는 아주 최근에 연구되고 있는 분야입니다.
아주 좋은 질문을 해 주셨습니다.

00:32:46.284 --> 00:32:54.354
그러므로 momentum이 좁고 깊은 minima를 무시해 버리는 것은
버그가 아니라 momentum의 특징이라고 할 수 있습니다.

00:32:55.979 --> 00:32:59.979
아직 확실하진 않지만(믿거나 말거나)
이는 momentum의 좋은 점이라고 할 수 있겠습니다.

00:33:00.825 --> 00:33:04.316
자 그리고 일반 momentum와 Nesterov이 조금 다르게
움직이는 것을 볼 수 있습니다.

00:33:04.316 --> 00:33:12.715
이는 Nesterov에서 추가된 수식 때문입니다.  일반 momentum에
비해서 overshooting이 덜 한 것을 알 수 있습니다.

00:33:14.683 --> 00:33:20.068
최적화 방법 중에 AdaGrad도 있습니다.

00:33:20.068 --> 00:33:25.292
현재 Stanford에 계시는 John Duchi 교수님께서
Ph.D 시절에 제안하신 방법입니다.

00:33:25.292 --> 00:33:37.663
AdaGrad는 훈련도중 계산되는 gradients를 활용하는 방법입니다.

00:33:39.569 --> 00:33:43.957
Adagrad는 velocity term 대신에
grad squared term을 이용합니다.

00:33:43.957 --> 00:33:49.199
그리고 학습 도중에 계산되는 gradient에
제곱을 해서 계속 더해줍니다.

00:33:49.199 --> 00:33:57.449
그리고 Update를 할때 Update term을
앞서 계산한 gradient 제곱 항으로 나눠줍니다.

00:33:59.334 --> 00:34:07.261
Condition number인 경우 빨간색 박스 안의 값은 어떨까요?

00:34:08.393 --> 00:34:12.560
[학생이 대답]

00:34:16.256 --> 00:34:22.904
2차원 좌표가 있다고 해 봅시다. 그 중 한 차원은 항상 gradient가
높은 차원입니다. 그리고 다른 하나는 항상 작은 gradient를 가집니다.

00:34:22.904 --> 00:34:35.181
Small dimension에서는 gradient의 제곱 값 합이 작습니다.
이 작은 값이 나눠지므로 가속도가 붙게 됩니다.

00:34:35.181 --> 00:34:45.924
Large dimension에서는 gradient가 큰 값 이므로 큰 값이
나눠지게 되겠죠. 그러므로 속도가 점점 줄어듭니다.

00:34:45.924 --> 00:34:56.093
하지만 AdaGrad에는 문제가 하나 있습니다. 학습이 계속 진행되면
어떻게 될까요? 학습 횟수 t가 계속 늘어나는 것입니다.

00:34:56.094 --> 00:34:58.391
[학생이 대답]

00:34:58.391 --> 00:35:02.239
AdaGrad는 step을 진행할수록 값이 점점 작아집니다.

00:35:02.239 --> 00:35:09.895
update 동안 gradient의 제곱이 계속해서 더해집니다. 때문에
이 값(estimate)은 서서히(monotonically) 증가하게 됩니다.

00:35:09.895 --> 00:35:15.359
이는 Step size를 점점 더 작은 값이 되게 합니다.

00:35:15.359 --> 00:35:20.334
손실함수가 convex한 경우에 점점 작아지는 것은
정말 좋은 특징이 될 수 있습니다.

00:35:20.334 --> 00:35:28.125
convex case에서는 minimum에 근접하면 서서히
속도를 줄여서 수렴할 수 있게 하면 좋겠죠

00:35:28.125 --> 00:35:31.192
Convex case에서는 좋은 특징이라 할 수 있습니다.

00:35:31.192 --> 00:35:42.007
하지만 non-convex case에서는 문제가 될 수 있습니다. 가령
saddle point에 걸려버렸을 때 AdaGrad는 멈춰버릴 수 있습니다.

00:35:42.007 --> 00:35:48.678
AdaGrad의 변형이 RMSProp입니다.
앞서 언급한 문제를 개선시킨 방법입니다.

00:35:48.678 --> 00:35:53.390
RMSProp에서는 AdaGrad의
gradient  제곱 항을 그대로 사용합니다.

00:35:53.390 --> 00:36:01.085
하지만 이 값들을 그저 누적만 시키는 것이 아니라
기존의 누적 값에 decay_rate를 곱해줍니다.

00:36:01.085 --> 00:36:09.340
이 값은 기존의 momentum 수식과 유사하게 생겼습니다. 다만
gradients의 제곱을 계속해서 누적해 나갑니다.

00:36:09.340 --> 00:36:20.361
RMSProp에서는 gradient 제곱 항에 쓰는 decay rate는
보통 0.9 또는 0.99정도를 자주 사용합니다.

00:36:20.361 --> 00:36:26.601
그리고 '현재 gradient의 제곱'은 (1 - decay rate) 를
곱해줘서 더해줍니다.

00:36:26.601 --> 00:36:37.193
RMSProp은 gradient 제곱을 계속 나눠준다는 점에서
AdaGrad와 유사합니다.

00:36:37.193 --> 00:36:44.070
이를 통해 step의 속도를 가속/감속 시킬 수 있습니다.

00:36:44.070 --> 00:36:52.411
하지만 RMSProp의 경우에는 위와 같은 특징으로
점점 속도가 줄어드는 문제를 해결할 수 있었습니다.

00:36:56.455 --> 00:37:04.173
이 예제에서 SGD는 검정색이고 momentum은 파란색
그리고 RMSProp은 빨간색입니다.

00:37:04.173 --> 00:37:12.263
RMSProp이나 momentum은 기본 SGD보다는 훨씬 더 좋습니다.
하지만 이 둘의 행동양상은 조금 다릅니다.

00:37:12.263 --> 00:37:17.488
momentum의 경우에는 overshoots한 뒤에
다시 minima로 돌아옵니다.

00:37:17.488 --> 00:37:26.392
RMSProp은 각 차원마다의 상황에 맞도록 적절하게
궤적(trajectory)을 수정시킵니다.

00:37:26.392 --> 00:37:34.412
여러분들한테는 안보이시겠지만 지금 이 그림에는 초록색으로
AdaGrad도 있습니다. 동일한 Learning rate로 말입니다.

00:37:34.412 --> 00:37:38.606
하지만 Learning rates가 점차 감소하기 때문에 RMSProp에
가려서 보이지 않습니다.

00:37:38.606 --> 00:37:45.553
실제로 AdaGrad는 잘 쓰이지는 않습니다. 그리고 이런 식의
비교는 사실 AdaGrad에게는 불공정합니다.

00:37:46.392 --> 00:37:52.558
아마도 AdaGrad의 Learning rate를 늘리게 되면
RMSProp과 비슷한 동작을 할 것입니다.

00:37:52.558 --> 00:37:57.148
하지만 일반적으로 Nerural Network를 학습시킬 때
AdaGrad를 잘 사용하지는 않습니다.

00:37:57.148 --> 00:37:57.981
질문 있나요?

00:37:57.981 --> 00:37:59.796
[학생이 질문]

00:37:59.796 --> 00:38:04.387
이 예시에서의 문제는 convex case입니다.
(convex인데 왜 Adagrad에게 불리한지)

00:38:07.146 --> 00:38:12.003
하지만 learning rates가 서로 상이하기 때문입니다.

00:38:12.003 --> 00:38:17.290
때문에 여러 알고리즘 간에 '같은 Learning rates' 를 가지고
AdaGrad 를 visualization하는 것은 공정하지 못합니다.

00:38:17.290 --> 00:38:23.132
visualization을 하고자 한다면 알고리즘 별로
learning rates를 조정하는 것이 좋습니다.

00:38:27.970 --> 00:38:35.403
자 우리는 momentum이라는 방법을 알아봤습니다.
velocity를 이용해서 step을 조절하는 방법이었습니다.

00:38:35.403 --> 00:38:43.744
AdaGrad와 RMSProp은 momentum과 다른 방식을 사용하죠.
gradients의 제곱을 나눠주는 방식으로 step을 조절했습니다.

00:38:43.744 --> 00:38:46.658
이 둘은(momentum 계열 vs Ada계열)
모두 괜찮은 아이디어인 것 같습니다.

00:38:46.658 --> 00:38:50.898
그렇다면 이 두 방법을 조합해보면 어떻까요?
아마 훨씬 더 좋은 방법이 될 것 같습니다.

00:38:50.898 --> 00:38:56.741
여기 Adam 이라는 알고리즘이 있습니다. 여기 수식은
Adam과 "유사한" 알고리즘이라고 보시면 됩니다.

00:38:56.741 --> 00:39:01.119
앞으로 몇 장의 슬라이드를 통해서 '진짜' Adam
이 되도록 조금씩 바꿔 볼 것입니다.

00:39:01.119 --> 00:39:06.888
Adam은 first moment와 second moment을 이용해서
이전의 정보(estimate)를 유지시킵니다.

00:39:06.888 --> 00:39:14.667
빨간색 first moment는 gradient의 가중 합입니다.

00:39:14.667 --> 00:39:22.741
그리고 second moment는 AdaGrad이나 RMSProp처럼
gradients의 제곱을 이용하는 방법입니다.

00:39:22.741 --> 00:39:28.621
Adam으로 Update를 진행하게 되면
우선 first moment는 velocity를 담당합니다.

00:39:28.621 --> 00:39:37.281
그리고  sqrt(second moment)를 나눠주는데
second moment는 gradient의 제곱 항입니다.

00:39:38.128 --> 00:39:46.269
Adam은 마치 RMSProp + momentum 같아 보입니다. 즉
momentum +  second squared gradients 이죠

00:39:46.269 --> 00:39:51.989
이 두 종류의 유용한 특징을 모두 이용하는 것입니다.
하지만 여기에도 문제가 하나 있습니다.

00:39:51.989 --> 00:40:06.134
초기 step 에서는 어떤 일이 발생할까요?
초기에 second moment를 0으로 초기화합니다.

00:40:06.134 --> 00:40:16.803
second moment를 1회 Update 하고 난 후를 생각해봅시다.
beta2는 decay_rate로 .9또는 .99로 1에 가까운 값입니다.

00:40:18.235 --> 00:40:22.867
그렇기 때문에 1회 업데이트 이후에도 second moment는
여전히 0에 가깝습니다.

00:40:22.867 --> 00:40:32.377
update step에서 second moment로 나누게 되는데 나눠주는
값이 크기 때문에 초기 step이 엄청나게 커지게 됩니다.

00:40:32.377 --> 00:40:37.768
중요한 것은 이 커진 step이 실제로 손실함수가
가파르기 때문(geometry)이 아니라는 것입니다.

00:40:37.768 --> 00:40:43.422
이 값은 second moment을 0으로 초기화 시켰기 때문에
발생하는 '인공적인' 현상입니다.

00:40:43.422 --> 00:40:44.322
질문 있나요?

00:40:44.322 --> 00:40:48.489
[학생이 질문]

00:40:52.832 --> 00:41:00.365
first moment도 second moment처럼 초기에
엄청 작은 값일 것입니다. 따라서

00:41:00.365 --> 00:41:02.906
learning rate에 '엄청 작은 값'을 곱하고(first moment)
'엄청 작은 값의 제곱근(second)'을 나누면 어떻게 될까요?

00:41:02.906 --> 00:41:05.746
어쩌면 서로 상쇄시킬 수 있고. 상쇄됀다면
문제는 해결되는 것이죠.

00:41:05.746 --> 00:41:13.632
예 사실입니다. 경우에 따라서 서로 상쇄될 수도 있습니다. 하지만
간혹 엄청 큰 step이 발생하는 경우도 생길 수 있습니다.

00:41:13.632 --> 00:41:16.245
하지만 한번 발생하면 정말 나쁜 상황일 것입니다.

00:41:16.245 --> 00:41:19.533
가령 여러분이 제대로 초기화를 해주지 않아서
아주 큰 step이 발생했다면

00:41:19.533 --> 00:41:26.145
초기화가 엉망이 될 것이고 아주 엉뚱한 곳으로 이동할 수도
있습니다. 결국 수렴할 수 없게 될 수도 있습니다.

00:41:26.145 --> 00:41:27.165
질문 있나요?

00:41:27.165 --> 00:41:30.915
[학생이 질문]

00:41:30.915 --> 00:41:37.847
질문은 수식의 10^-7이 무엇인지 입니다. 저 값은
AdaGrad, RMSProp, Adam에서 등장합니다.

00:41:37.847 --> 00:41:42.187
우리는 현재 어떤 값으로 '나눗셈' 를 하고 있습니다.
하지만 그 값이 항상 0이 아니라는 보장은 없죠

00:41:42.187 --> 00:41:48.609
따라서 분모에 작은 양수 값을 더해줘서 0이 되는 것을
사전에 방지할 수 있습니다.

00:41:48.609 --> 00:41:56.012
이 또한 하이퍼파라미터 이긴 하지만 큰 영향력은 없습니다.
보통 10^-7이나 10^-8정도를 사용하면 잘 동작합니다.

00:41:57.967 --> 00:42:05.511
Adam은 초기 Step이 엄청 커져 버릴 수 있고
이로 인해 잘못될 수도 있다고 했습니다.

00:42:05.511 --> 00:42:12.510
Adam을 이를 해결하기 위해 보정하는 항을 추가합니다.
(bias correction term )

00:42:12.510 --> 00:42:22.619
first/second moments를 Update하고 난 후 현재 Step에
맞는 적절한 unbiased term 을 계산해 줍니다.

00:42:22.619 --> 00:42:29.550
실제 Adam은 first/second moment만 계산하는 것이 아니라
이렇게 unbiased term을 넣어줘야 합니다.

00:42:29.550 --> 00:42:33.167
지금 보시는 부분이 '완전한 Adam' 이라 할 수 있겠습니다.

00:42:33.167 --> 00:42:45.550
그리고 Adam은 엄청 좋습니다. 다양한 문제들에도 정말 잘 동작합니다.
저는 어떤 문제에서도 기본 알고리즘으로 Adam을 사용하곤 합니다.

00:42:45.550 --> 00:42:53.088
특히나 beta_1 = 0.9, beta_2 = 0.999로 설정하고
Learning rate를 E-3나 E-4 정도로만 설정해 놓으면

00:42:53.088 --> 00:42:58.797
거의 모든 아키텍쳐에서 잘 동작하는
기본 설정으로 아주 제격입니다.

00:42:58.797 --> 00:43:03.518
일반적으로 Adam으로 시작해 보는 것은 정말 좋습니다.

00:43:03.518 --> 00:43:05.949
[웃음]

00:43:05.949 --> 00:43:11.634
자 동일한 환경에서 SGD, Momentum, RMSProp,
Adam을 한번 비교해 봅시다.

00:43:11.634 --> 00:43:18.094
보라색 Adam을 한번 봅시다. momentum과 RMSProp을
짬뽕시켜 놓은듯한 모습입니다.

00:43:18.094 --> 00:43:25.175
Adam이 momentum처럼 overshoots하긴 하지만
momentum만큼 엄청 심하지는 않습니다.

00:43:25.175 --> 00:43:33.268
그리고 Adam은 RMSProp같은 특징도 가지고 있습니다. 각 차원의
상황을 따로 고려해서 Step을 이동합니다.

00:43:33.268 --> 00:43:37.706
여기 단순한 2차원 예제에서 수렴하는 것을 보면
그놈이 그놈같아 보일 수는 있지만

00:43:37.706 --> 00:43:42.832
확실한 것은 Adam이 momentum스러우면서도
RMSProp스럽다는 것입니다.

00:43:45.042 --> 00:43:48.709
Optimization 알고리즘에 대한 질문 있으신가요?

00:43:50.048 --> 00:43:56.606
[학생이 질문]

00:43:56.606 --> 00:44:03.193
질문은 Adam이 해결하지 못하는 것은 무엇인지 입니다.
Neural networks는 여전이 엄청 크고 학습은 오래걸립니다.

00:44:04.744 --> 00:44:07.098
Adam을 쓰더라도 여전히 문제점들이 있습니다.

00:44:07.098 --> 00:44:11.979
가령 손실함수가 타원형일 경우를 생각해 봅시다.

00:44:11.979 --> 00:44:19.219
Adam을 이용하면 각 차원마다 적절하게 속도를 높히고
줄이면서 '독립적으로' step을 조절할 것입니다.

00:44:19.219 --> 00:44:26.576
하지만 이 타원이 축 방향으로 정렬되어 있지 않고
기울어져 있다고 생각해 봅시다.

00:44:26.576 --> 00:44:29.887
이 경우에도 Adam은 차원에 해당하는 축 만을
조절할 수 있습니다.

00:44:30.935 --> 00:44:38.131
이는 차원을 회전시킨 다음에 수평/수직 축으로만 늘렸다 줄였다
하는 것입니다. 회전을 시킬수는 없죠

00:44:38.131 --> 00:44:48.732
이러한 회전된 타원(poor conditioning) 문제는 Adam을 비롯한
다른 여러 알고리즘들도 다룰 수 없는 문제입니다.

00:44:51.356 --> 00:44:57.706
지금까지의 모든 Opimization 알고리즘은
learning rate 이라는 하이퍼파라미터를 가지고 있었습니다.

00:44:57.706 --> 00:45:01.828
지난 시간이 이 그림을 본 적 있을 것입니다.

00:45:01.828 --> 00:45:05.097
Learning rate가 지나치게 높으면
노란색 처럼 솟구치게 되겠죠

00:45:05.097 --> 00:45:09.629
파란색 처럼 너무 낮으면
수렴하는데 너무 오래걸립니다.

00:45:09.629 --> 00:45:11.933
하지만 learning rate를 잘 고르는 것은 상당히 까다롭습니다.

00:45:13.712 --> 00:45:19.308
우리는 학습 과정에서 learning rate 하나를 정해놓고
시작해야 하기 때문에 잘 고르는게 참 어렵습니다.

00:45:19.308 --> 00:45:29.705
 learning rates dacay 전략을 사용해 볼 수 있습니다.
각각의 learning rates의 특성을 적절히 이용하는 것이죠

00:45:29.705 --> 00:45:39.366
처음에는 learning rates를 높게 설정한 다음에 학습이 진행될수록
learning rates를 점점 낮추는 것입니다.

00:45:39.366 --> 00:45:46.795
다양한 전략을 시도해 볼 수 있지만 가령 100,000 iter에서
learning rates를 낮추고 학습시키는 것입니다.(step decay)

00:45:46.795 --> 00:45:52.579
혹은 exponential decay 처럼 학습과정 동안에
꾸준히 learning rate를 낮출 수도 있습니다.

00:45:52.579 --> 00:45:57.598
꾸준히 learning rate를 감소시키는 것에는
다양한 전략이 있을 수 있습니다.

00:45:57.598 --> 00:46:04.347
오른쪽의 그림을 보시기 바랍니다. Resnet 논문에 있는
그림입니다. Loss가 계속 내려가고 있습니다.

00:46:04.347 --> 00:46:07.898
그리고 어느순간 평평해 지는 듯 하더니 다시 또 내려가는
것을 반복하는 것을 알 수 있습니다.

00:46:07.898 --> 00:46:11.312
Resnet 논문에서는 step decay learning rate 전략을
사용한 것입니다.

00:46:11.312 --> 00:46:18.401
평평해지다가 갑자기 내려가는 구간은
Learning rate를 낮추는 구간입니다.

00:46:18.401 --> 00:46:26.243
learning rate를 언제 낮춰야 하는지를 생각해보면, 현재 수렴을
잘 하고 있는 상황에서 gradient가 점점 작아지고 있는 것입니다.

00:46:26.243 --> 00:46:28.066
learning rate가 너무 높아서 더 깊게 들어가지 못합니다.
(bouncing around too much)

00:46:28.066 --> 00:46:32.745
이 상황에서  learning rate를 낮추게 되면 속도가 줄어들 것이고
지속해서 Loss를 내려갈 수 있을 것입니다.

00:46:32.745 --> 00:46:36.475
실제로 상당히 도움이 되는 방법입니다.

00:46:36.475 --> 00:46:44.973
그리고 한가지 말씀드릴 것은 learning rate decay는
Adam 보다는 SGD Momentum을 사용할 때 자주 씁니다.

00:46:44.973 --> 00:46:50.458
또 한가지 말씀드릴 것은 learning rate decay는
부차적인 (second-order ) 하이퍼파라미터 라는 것입니다.

00:46:50.458 --> 00:46:53.324
일반적으로 learning-rate decay를 학습 초기부터
고려하지는 않습니다.

00:46:53.324 --> 00:47:00.877
보통 학습 초기에는 learning rate decay가 없다고 생각하고
learning rate를 잘 선택하는 것이 중요합니다.

00:47:00.877 --> 00:47:06.068
learning rate와 dacay 등을 cross-validate 하려고
한다면 문제가 너무 복잡해 집니다.

00:47:06.068 --> 00:47:10.581
learning rate decay를 설정하는 순서는
우선 decay 없이 학습을 시켜 봅니다.

00:47:10.581 --> 00:47:15.427
그리고 Loss curve를 잘 살피고 있다가 decay가 필요한 곳이
어디인지 고려해 보는 것이 좋습니다.

00:47:16.860 --> 00:47:24.948
지금까지 배운 Optimization 알고리즘들을 모두
1차미분을 활용한(first-order) 방법이었습니다.

00:47:24.948 --> 00:47:33.064
그림처럼 1차원의 손실함수가 있다고 생각해 봅시다.
우리는 지금 빨간색 점에 있는 것입니다.

00:47:33.064 --> 00:47:36.057
이 점에서 gradient 를 계산하겠죠

00:47:36.057 --> 00:47:40.722
이 gradient 정보를 이용해서 우리는 손실함수를
선형함수로 근사시킵니다.

00:47:40.722 --> 00:47:44.208
이는 일종의 1차 테일러 근사입니다.
(first-order Taylor apporximation)

00:47:44.208 --> 00:47:51.814
우리는 이 1차 근사함수를 실제 손실함수라고 가정하고
Step을 내려갈 것입니다.

00:47:51.814 --> 00:47:57.353
하지만 이 근사함수로는 멀리갈 수 없습니다.

00:47:57.353 --> 00:48:04.509
현재 우리가 사용하는 정보는 1차 미분값일 뿐입니다.
그리고 우리는 조금 더 괜찮은 방법을 생각해 볼 수도 있을 것입니다.

00:48:04.509 --> 00:48:11.248
2차 근사 (second-order approximation)의 정보를
추가적으로 활용하는 방법이 있습니다.

00:48:11.248 --> 00:48:18.449
이는 2차 테일러 근사 함수가 될 것이고 이 함수는
2차함수의 모양입니다.

00:48:18.449 --> 00:48:22.281
2차 근사를 이용하면 minima에 더 잘 근접할 수 있습니다.
you're really happy

00:48:22.281 --> 00:48:25.769
이것이 바로 2nd-order optimization의 기본 아이디어입니다.

00:48:25.769 --> 00:48:30.489
방금 예시는 다차원으로 확장시켜보면 이를
'Newton step' 이라고 합니다.

00:48:30.489 --> 00:48:35.066
Hessian matrix를 계산합니다. 2차 미분값들로 된 행렬입니다.

00:48:35.066 --> 00:48:43.689
 Hessian matrix의 역행렬을  이용하게 되면 실제 손실함수의
2차 근사를 이용해 minima로 곧장 이동할 수 있을 것입니다.

00:48:43.689 --> 00:48:48.910
혹시 이 알고리즘이 다른 Optimization 알고리즘에 비해
특이한 것이 무엇인지 아시겠습니까?

00:48:48.910 --> 00:48:51.107
[학생이 대답]

00:48:51.107 --> 00:48:54.328
네 맞습니다. Learning rate가 없습니다.
That's kind of cool.

00:48:56.463 --> 00:49:00.664
지금 우리는 2차근사 함수를 만들었고 이 2차근사 함수의
minima로 이동하는 것입니다.

00:49:00.664 --> 00:49:04.681
적어도 "기본적인 Newton's method" 에서는
learning rate는 불필요합니다.

00:49:04.681 --> 00:49:07.849
매 step마다 항상 minma를 향해 이동합니다.

00:49:07.849 --> 00:49:13.265
하지만 실제로는 learning rate가 필요합니다.
왜냐하면 2차 근사도 사실상 완벽하지 않기 때문이죠

00:49:13.265 --> 00:49:21.055
minima로 이동하는게 아니라 'minima의 방향'으로 이동하기 때문이죠
어쨌든 기본버전에는 learning rate가 없습니다.

00:49:23.994 --> 00:49:27.366
하지만 불행하게도 Deep learning에서는 사용할 수 없습니다.

00:49:27.366 --> 00:49:34.519
왜냐하면 Hessian matrix는 N x N 행렬입니다.
N은 Network의 파라미터 수입니다.

00:49:34.519 --> 00:49:38.498
N이 1억이면 1억의 제곱만큼 존재할 것입니다.

00:49:38.498 --> 00:49:42.046
이를 메모리에 저장할 방법은 없으며
또한 역행렬계산도 불가능 할 것입니다.

00:49:42.046 --> 00:49:46.486
그래서 실제로는 'quasi-Newton methods' 를 이용합니다.

00:49:46.486 --> 00:49:52.725
Full Hessian을 그대로 사용하기 보다 근사시킵니다.
Low-rank approximations 하는 방법입니다.

00:49:52.725 --> 00:49:57.092
여러분도 앞으로 간혹 접하게 될 것입니다.

00:49:57.092 --> 00:50:03.487
L-BFGS도 second-order optimizer입니다. 이 방법도
Hassian을 근사시켜서 사용하는 방법입니다.

00:50:03.487 --> 00:50:11.205
L-BFGS도 여러분이 가끔씩 보게될텐데 사실상
DNN에서는 잘 사용하지 않습니다.

00:50:11.205 --> 00:50:16.410
왜냐하면 L-BFGS에서 2차근사가 stochastic case에서
잘 동작하지는 않기 때문입니다.

00:50:16.410 --> 00:50:20.616
그리고 L-BFGS는 non-convex problems에도
적합하지 않습니다.

00:50:20.616 --> 00:50:23.142
더 깊게는 들어가지 않겠습니다.

00:50:23.142 --> 00:50:29.022
실제로는 Adam을 제일 많이 씁니다.

00:50:29.022 --> 00:50:38.974
하지만 full batch update가 가능하고 stochasticity이
적은 경우라면  L-BFGS가 좋은 선택이 될 수 있습니다.

00:50:38.974 --> 00:50:43.181
L-BFGS가 Neural network를 학습시키는데 그렇게
많이 사용되지는 않지만

00:50:43.181 --> 00:50:47.251
앞으로 보게될 Sytle tranfer와 같은 알고리즘에
L-BFGS을 종종 사용할 수 있습니다.

00:50:47.251 --> 00:50:54.356
Sytle tranfer같은 stochasticity와 파라미터가
적은 경우에서 Optimization을 해야할 경우에 말이죠

00:50:55.834 --> 00:51:00.992
지금까지 이야기했던 모든 것들을 전부 training error를
줄이기 위한 방법들이었습니다.

00:51:02.344 --> 00:51:07.452
optimization 알고리즘들은 training error를 줄이고
손실함수를 최소화시키기 위한 역할을 수행합니다.

00:51:07.452 --> 00:51:10.403
하지만 사실 우리는 Training error에 크게 신경쓰지 않습니다.

00:51:10.403 --> 00:51:13.203
대신에 "한번도 보지 못한 데이터"에 대한 성능이 더 중요하죠

00:51:13.203 --> 00:51:16.817
우리가 원하는 것은 train/test error의 격차를
줄이는 것입니다.

00:51:16.817 --> 00:51:21.228
질문은 바로 우리가 손실함수 최적화를
이미 모두 끝마친 상황에서

00:51:21.228 --> 00:51:25.535
'한번도 보지 못한 데이터' 에서의 성능을
올리기 위해서는 어떻게 해야 할까요?

00:51:28.497 --> 00:51:33.617
가장 빠르고 쉬운 길은 바로 모델 앙상블입니다.

00:51:33.617 --> 00:51:36.767
Machine learning 분야에서 종종 사용하는 기법입니다.

00:51:36.767 --> 00:51:44.588
아이디어는 아주 간단합니다. 모델을 하나만 학습시키지 말고
10개의 모델을 독립적으로 학습시키는 것입니다.

00:51:44.588 --> 00:51:51.333
결과는 10개 모델 결과의 평균을 이용합니다.

00:51:53.562 --> 00:52:01.555
모델의 수가 늘어날수록 overfitting 줄어들고
성능이 조금씩 향상됩니다. 보통 2%정도 증가하죠

00:52:01.555 --> 00:52:05.302
엄청나게 큰 변화는 아니지만 상당히
일관적으로 이 정도 늘어납니다.

00:52:05.302 --> 00:52:13.263
Imagenet 같은 대회에서는 모델의 성능을 최대화 시키기 위해서
이러한 앙상블 기법을 사용하는 모습을 볼 수 있습니다.

00:52:14.488 --> 00:52:20.482
조금 더 창의적인 방법도 있습니다. 모델을 독립적으로
학습시키는 것이 아니라

00:52:20.482 --> 00:52:25.928
학습 도중 중간 모델들을 저장(sanpshots)하고
앙상블로 사용할 수 있습니다.

00:52:25.928 --> 00:52:29.804
그리고 Test time에는 여러 snapshots에서 나온 예측값들을
평균을 내서 사용합니다.

00:52:29.804 --> 00:52:33.244
이런 snapshots은 Training 과정 중간에 저장하는 것입니다.

00:52:34.133 --> 00:52:43.210
이번주에 ICLR에 좀 더 향상된 앙상블 알고리즘이 발표되었습니다.
이 방법은 아주 독특한 Learning rate 스케줄을 이용합니다.

00:52:43.210 --> 00:52:47.996
Learning rate를 엄청 낮췄다가 다시 엄청 높혔다가를 반복합니다.

00:52:47.996 --> 00:52:57.631
이 논문의 아이디어는 이런 방식으로 손실함수에 다양한 지역에
수렴할 수 있도록 만들어 줍니다.

00:52:58.717 --> 00:53:05.532
이런 앙상블 기법으로 모델을 한번만 Train시켜도 좋은
성능을 얻을 수 있게 하는 방법입니다.

00:53:05.532 --> 00:53:11.198
질문있나요?

00:53:25.388 --> 00:53:33.413
질문은 모델간의 Loss 차이가 크면 한쪽이 overfiting 일 수 있으니
별로 안좋고, 또 차이가 작아도 안좋지 않냐는 것입니다.

00:53:33.413 --> 00:53:37.446
그러니 좋은 앙상블 결과를 위해서라면 모델 간의 최적의 갭을 찾는 것이
중요하지 않느냐는 것입니다.

00:53:37.446 --> 00:53:39.132
사실 갭이 중요한 것이 아닙니다.

00:53:39.132 --> 00:53:44.019
중요한 것은 validation set의
성능을 최대화시키는 것입니다.

00:53:44.019 --> 00:53:54.995
하지만 우선 갭을 신경쓰지 않고 모델을 조금 더 Overfitting 시킬 수
있다면 아마 더 좋은 성능을 낼 수 있을 것입니다.

00:53:54.995 --> 00:54:02.720
Validation set 성능과 이 갭 사이에는 묘한 관계가 있긴 하지만
오로지 Validation set 성능만 신경쓰면 됩니다.

00:54:02.720 --> 00:54:03.735
질문있나요?

00:54:03.735 --> 00:54:07.004
[학생이 질문]

00:54:07.004 --> 00:54:09.528
질문은 앙상블 모델마다 하이퍼파라미터를 동일하게
줘야 하는지 입니다.

00:54:09.528 --> 00:54:12.234
좋은 질문이군요. 그렇지 않을 수도 있습니다.

00:54:12.234 --> 00:54:19.614
다양한 "모델 사이즈", "learning rate", 그리고 "다양한
regularization 기법" 등을 앙상블 할 수 있습니다.

00:54:19.614 --> 00:54:22.614
실제로 그렇게 사용하기도 합니다.

00:54:23.496 --> 00:54:31.769
또 다른 방법으로는 학습하는 동안에 파라미터의
exponentially decaying average를 계속 계산합니다.

00:54:31.769 --> 00:54:35.778
이 방법은 학습중인 네트워크의
smooth ensemble 효과를 얻을 수 있습니다.

00:54:35.778 --> 00:54:41.649
checkpoints에서의 파라미터를 그대로 쓰지 않고
smoothly decaying average를 사용하는 방법입니다.

00:54:41.649 --> 00:54:45.262
이를 Polyak averaging라고 합니다. 때때로
조금의 성능향상을 보일 수 있습니다.

00:54:45.262 --> 00:54:50.838
이 또한 시도해볼만한 방법이긴 하지만
실제로 자주 사용하지는 않습니다.

00:54:50.838 --> 00:54:55.778
그렇다면 앙상블이 아닌 단일 모델의 성능을
향상시키기 위해서는 어떻게 해야 할까요?

00:54:57.229 --> 00:55:02.503
앙상블을 하려 한다면 test time에 10개의 모델을
돌려야 할 수도 있습니다. 그렇게 좋은 방법은 아니죠

00:55:02.503 --> 00:55:06.219
단일 모델의 성능을 올리는 것이
우리가 정말 원하는 것입니다.

00:55:06.219 --> 00:55:08.237
 바로 regularization입니다.

00:55:08.237 --> 00:55:11.954
우리가 모델에 어떤 것을 추가할 텐데
모델이 training data에 fit하는 것을 막아줄 것입니다.

00:55:11.954 --> 00:55:16.203
그리고 한번도 보지 못한 데이터에서의
성능을 향상시키는 방법입니다.

00:55:16.203 --> 00:55:23.515
우리는 이미 몇 가지 regularization 기법을 살펴봤습니다.
Loss에 추가적인 항을 삽입하는 방법이었습니다.

00:55:23.515 --> 00:55:29.738
손실함수에서 기존의 항은 training data에 fit하려 하고
다른 하나는 regularization term 이죠

00:55:29.738 --> 00:55:33.032
과제에서도 있었죠  L2 regularization이
대표적인 예입니다.

00:55:34.804 --> 00:55:43.001
앞서 강의에서도 말씀드렸듯이 L2 regularization은
Neural networks에는 잘 어울리지 않습니다.

00:55:43.922 --> 00:55:47.982
때문에 조금 다른 것을 사용하죠

00:55:47.982 --> 00:55:53.376
Neural network에서 가장 많이 사용하는 regularization은
바로 dropout입니다.

00:55:53.376 --> 00:55:55.080
Dropout은 정말 간단합니다.

00:55:55.080 --> 00:56:02.264
forward pass 과정에서 임의로 일부 뉴런을
0으로 만드는 것입니다.

00:56:02.264 --> 00:56:08.688
forward pass 할때마다 0이 되는 뉴런이 바뀝니다.
Dropout은 한 레이어씩 진행하게 됩니다.

00:56:08.688 --> 00:56:15.193
한 레이어의 출력을 전부 구합니다. 그리고 임의로 일부를 0으로
만듭니다. 그리고 다음 레이어로 넘어가는 식입니다.

00:56:15.193 --> 00:56:22.445
왼쪽에는 dropout이 없고 오른쪽은 dropout이
적용된 경우 입니다.

00:56:22.445 --> 00:56:30.400
오른쪽 모델은 동일한 네트워크의 더 작아진 버전 처럼 생겼습니다.
오로지 뉴런의 일부만 사용하고 있습니다.

00:56:30.400 --> 00:56:35.746
forward pass iteration 마다 그 모양은 계속 바뀝니다.

00:56:35.746 --> 00:56:36.732
질문 있나요?

00:56:36.732 --> 00:56:40.899
[학생이 질문]

00:56:43.694 --> 00:56:46.375
질문은 지금 무엇을 0으로 놓는 것인지 입니다.
activations을 0으로 설정하는 것입니다.

00:56:46.375 --> 00:56:51.731
각 레이어에서
next activ= prev activ * weight 죠

00:56:51.731 --> 00:57:01.592
현재 activations의 일부를 0으로 만들면
다음 레이어의 일부는 0과 곱해질 것입니다.

00:57:01.592 --> 00:57:03.155
질문 있나요?

00:57:03.155 --> 00:57:06.702
[학생이 질문]

00:57:06.702 --> 00:57:08.751
질문은 어떤 종류의 레이어에서 이를 사용하는지 입니다.

00:57:08.751 --> 00:57:14.454
Dropout은 fc layer에서 흔히 사용합니다.
하지만 conv layers에서도 종종 볼 수 있습니다.

00:57:14.454 --> 00:57:23.423
Conv net의 경우에서는 전체 feature map에서
dropout을 시행합니다.

00:57:24.455 --> 00:57:30.117
conv layer의 경우에 여러 channels이 있기 때문에
일부 channel 자체를 dropout 시킬 수도 있겠습니다.

00:57:32.059 --> 00:57:38.480
실제로 Dropout 구현은 아주 쉽습니다.
두 줄이면 충분합니다.

00:57:38.480 --> 00:57:41.572
여기 3-layer neural network 예제가 있습니다.
여기에 Dropout을 추가했습니다.

00:57:41.572 --> 00:57:49.460
임의로 0으로 설정하는 부분만 추가하면 됩니다.
구현하기 아주 쉽습니다.

00:57:49.460 --> 00:57:52.138
그렇다면 dropout이 도대체 왜 좋을까요?

00:57:52.138 --> 00:57:58.067
일부 값들을 0으로 만들면서 training time의 네트워크를
심각하게 훼손시키고 있습니다.

00:57:58.067 --> 00:58:00.988
이런 일이 어떻게 가능할까요?

00:58:00.988 --> 00:58:08.532
대략적으로 말씀드리면, 특징들 간의
상호작용(co-adaptation)을 방지한다고 볼 수 있습니다.

00:58:09.622 --> 00:58:15.853
자 우선 우리에게 고양이를 분류하는 어떤 네트워크가 있다고 해봅시다.

00:58:15.853 --> 00:58:21.066
어떤 뉴런은 눈에대해, 어떤 뉴런은 꼬리에대해, 또 어떤 뉴런은
고양이의 털에 대해 학습하는 것을 상상해 볼 수 있을 것입니다.

00:58:21.066 --> 00:58:24.751
그리고 이 이미지가 고양이인지 아닌지를 이 정보들을
모두 취합해서 결정을 내리는 것입니다.

00:58:24.751 --> 00:58:32.831
Dropout을 적용하게 되면 네트워크가 어떤 일부
features에만 의존하지 못하게 해줍니다.

00:58:32.831 --> 00:58:37.725
대신에 모델이 "고양이다" 라고 예측할 때 다양한
features를 골고루 이용할 수 있도록 합니다.

00:58:37.725 --> 00:58:42.205
따라서 Dropout이 Overfitting을 어느정도
막아준다고 할 수 있겠습니다.

00:58:42.205 --> 00:58:50.347
그리고 최근 Dropout에 대한 새로운 해석이 나왔는데
단일 모델로 앙상블 효과를 가질 수 있다는 것입니다.

00:58:51.690 --> 00:58:58.745
자 여기 왼쪽의 Dropout을 적용한 네트워크를 살펴보면
뉴런의 일부만 사용하는 서브네트워크라는 것을 알 수 있습니다.

00:58:58.745 --> 00:59:03.391
Dropout으로 만들 수 있는 서브네트워크의
경우의 수가 정말 다양하다는 것을 알 수 있습니다.

00:59:03.391 --> 00:59:09.145
따라서 Dropout은 서로 파라미터를 공유하는 서브네트워크
앙상블을 동시에 학습시키는 것이라고 생각할 수 있습니다.

00:59:09.145 --> 00:59:13.790
하지만 뉴런의 수에 따라서 앙상블 가능한 서브네트워크의 수가
기하급수적으로 증가하기 때문에

00:59:13.790 --> 00:59:17.152
가능한 모든 서브네트워크를 사용하는것은 사실상 불가능합니다.

00:59:18.089 --> 00:59:24.788
Dropout은 아주 거대한 앙상블 모델을 동시에
학습 시키는 것이라고 볼 수 있겠습니다.

00:59:25.622 --> 00:59:29.128
그렇다면 Dropout을 사용하면 Test time에
어떤 일이 일어날까요?

00:59:29.128 --> 00:59:34.158
Dropout을 사용하게되면 기본적으로 Neural network의
동작 자체가 변하게 됩니다.

00:59:34.158 --> 00:59:42.850
기존의 Neural network는 가중치 w와 입력 x에
대한 함수(f) 였습니다.

00:59:42.850 --> 00:59:48.268
하지만 Dropout을 사용하면 Network에 z라는 입력이 추가됩니다.
z는 "random dropout mask" 입니다.

00:59:48.268 --> 00:59:52.732
z는 random입니다. 하지만 test time에 임의의 값을
부여하는 것은 좋지 않습니다.

00:59:52.732 --> 00:59:57.444
가령 여러분이 Facebook에서 일하고 있고 사람들이 업로드하는
이미지를 분류하려 한다고 해봅시다.

00:59:57.444 --> 01:00:03.092
오늘은 고양이라고 분류했던 이미지를 내일이 되서는
다른 이미지라고 분류한다고 하면 그닥 좋지 않은 상황이겠죠

01:00:03.092 --> 01:00:09.323
따라서 네트워크가 이미 학습된 네트워크의 Test time에는
이러한 임의성(stochasticity)은 적절하지 않습니다.

01:00:09.323 --> 01:00:12.093
대신 그 임의성(randomness)을 average out 시킵니다.

01:00:12.093 --> 01:00:18.131
이는 적분을 통해 randomness를 marginalize out시키는
것으로 한번 생각해 볼 수 있을 것입니다. 하지만 실제로는-

01:00:18.131 --> 01:00:24.368
이 적분을 다루기는 상당히 까다롭습니다.

01:00:24.368 --> 01:00:28.073
이 문제를 해결할 수 있는 간단한 방법 중 하나는
샘플링을 통해서 적분을 근사시키는 것인데요

01:00:28.073 --> 01:00:31.484
z를 여러번 샘플링해서 test time에 이를
average out 시키는 것입니다.

01:00:31.484 --> 01:00:36.040
하지만 이 방법도 Test time에서의 randomness을
만들어 내기 때문에 좋지 않은 방법입니다.

01:00:36.040 --> 01:00:41.423
고맙게도 dropout의 경우에는 일종의 locally cheap한 방법을
이용해서 이 적분식을 근사화시킬 수 있습니다.

01:00:41.423 --> 01:00:47.228
가령 여기 하나의 뉴런이 있습니다. 출력은 a 이고
입력 x, y가 있고 가중치 w_1, w_2가 있습니다.

01:00:47.228 --> 01:00:52.622
Test time에서 a는 w_1x + w_2y 입니다.

01:00:53.590 --> 01:01:00.645
자 그럼 이 네트워크를 dropout(p = 0.5) 를 적용해서
train 시킨다고 생각해 봅시다.

01:01:00.645 --> 01:01:06.317
train time에서의 기댓값은 아래와 같은 경우로
(analytically) 계산해 볼 수 있습니다.

01:01:07.712 --> 01:01:12.249
dropout mask에는 4가지 경우의 수가 존재합니다.
이제 그 값들을 4개의 마스크에 대해 평균화 시켜 줍니다.

01:01:12.249 --> 01:01:18.204
Train time에서 a의 기댓값은
1/2(w_1x + w_2y) 입니다.

01:01:19.075 --> 01:01:29.000
이 부분에서 test/train time 간의 기댓값이 서로 상이합니다.
train time의 기댓값은 test time의 절반밖에 안되죠

01:01:29.000 --> 01:01:34.883
Test time에서 stochasticity를 사용하지 않고
할 수 있는 값 싼(cheap) 방법 중 하나는

01:01:34.883 --> 01:01:40.736
대신에 dropout probability를 네트워크의 출력에 곱합니다.
자 이제 둘의 기댓값이 같아졌습니다.

01:01:40.736 --> 01:01:44.733
이 방법은 이전의 복잡한 적분식을 아주 저렴하게(cheap)
local approximation시킬 수 있는 방법입니다.

01:01:44.733 --> 01:01:48.576
실제로 많은 사람들이 Dropout을 사용할 때
이 방법을 많이 사용합니다.

01:01:49.715 --> 01:01:56.269
Dropout을 사용하게 되면 네트워크 출력에
dropout probability를 곱해줘야 합니다.

01:01:56.269 --> 01:01:59.393
Dropout에 대해 요약해보자면 Forward pass에 Dropout
을 추가시키는 것은 상당히 간단합니다.

01:01:59.393 --> 01:02:03.807
일부 노드를 무작위로 0으로 만들어주는데는
2줄이면 충분하죠

01:02:03.807 --> 01:02:10.209
그리고 Test time에서는 그저 값 하나만 곱해주면 됩니다.
(probability)

01:02:10.209 --> 01:02:16.613
Dropout은 상당히 간단합니다. 그리고 Neural network의
Regularization에 상당히 효과적이죠

01:02:16.613 --> 01:02:21.454
그리고 Dropout을 사용할 때 한가지 트릭을 생각해 볼 수 있습니다.
Dropout을 역으로 계산하는 것입니다 (inverted dropout)

01:02:22.665 --> 01:02:28.735
 Test time에는 곱하기 연산이 하나 추가되는 것은 상당히
신경쓰이는 일입니다. Test time에서는 계산효율이 중요합니다

01:02:28.735 --> 01:02:37.677
Test time에는 기존의 연산을 그대로 사용하고 대신 Train time
에서 p를 나눠줍니다. 보통 train은 GPU로 하기 때문이죠

01:02:37.677 --> 01:02:44.733
Train time에서는 곱하기 몇 번 추가되는 것에 별로 신경쓰지 않지만
Test time에서는 가능한 효율적으로 동작하길 원합니다.

01:02:44.733 --> 01:02:45.566
질문 있나요?

01:02:46.416 --> 01:02:56.777
[학생이 질문]

01:02:57.678 --> 01:03:02.212
질문은 dropout을 사용하게 되면 Train time에서
gradient에는 어떤 일이 일어나는지 입니다.

01:03:02.212 --> 01:03:06.583
Dropout이 0으로 만들지 않은 노드에서만
Backprop이 발생하게 됩니다.

01:03:06.583 --> 01:03:15.356
때문에 dropout을 사용하게 되면 전체 학습시간이 늘어납니다.
각 스텝마다 업데이드되는 파라미터의 수가 줄어들기 때문이죠

01:03:15.356 --> 01:03:22.287
다시 말해 Dropout을 사용하게 되면 전체 학습시간은 늘어나지만
모델이 수렴한 후에는 더 좋은 일반화 능력을 얻을 수 있습니다.

01:03:24.409 --> 01:03:32.810
사실 Dropout은 여기 보이는 일반적인 regularization 전략을
구체화시킨 하나의 예시에 불과합니다. 이 전략은 -

01:03:32.810 --> 01:03:37.482
Train time에는 네트워크에 무작위성(randomness)을 추가해
training data에 너무 fit하지 않게 합니다.

01:03:37.482 --> 01:03:41.037
네트워크를 마구잡이로 흩뜨려 놓으므로써
training data에 fit하는 것을 방해하는 것입니다.

01:03:41.037 --> 01:03:46.160
그리고 Test time에서는 randomness을 평균화 시켜서
generalization 효과를 주는 것입니다.

01:03:46.160 --> 01:03:53.927
Dropout이 Regularization에 가장 대표적인 예이긴 하지만
Batch normalization 또한 이와 비슷한 동작을 할 수 있습니다.

01:03:53.927 --> 01:04:00.755
Train time의 BN를 상기해보면 mini batch로 하나의 데이터가
샘플링 될 때 매번 서로 다른 데이터들과 만나게 됩니다.

01:04:00.755 --> 01:04:07.200
Train time에서는 각 데이터에 대해서 이 데이터를 얼마나 어떻게
정규화시킬 것인지에 대한 stochasticity이 존재했습니다.

01:04:07.200 --> 01:04:14.735
하지만 test time에서는 정규화를 mini batch 단위가 아닌
global 단위로 수행함으로써 stochasticity를 평균화 시킵니다.

01:04:14.735 --> 01:04:20.223
이런 특성 때문에 BN 은 Dropout과 유사한
Regularization 효과를 얻을 수 있었습니다.

01:04:20.223 --> 01:04:25.478
Train time에는 stochasticity(noise)가 추가되지만
Test time에서는 전부 평균화 되기 때문입니다.

01:04:25.478 --> 01:04:35.744
실제로 BN을 사용할 때는 Dropout을 사용하지 않습니다. BN에도
충분히 regularization 효과가 있기 때문이죠

01:04:35.744 --> 01:04:43.833
하지만 여전히 Dropout은 쓸모 있습니다. 우리가 자유롭게 조절할
수 있는 파라미터 p가 있기 때문이죠. BN에는 없는 것이죠

01:04:43.833 --> 01:04:48.928
이러한 Regularization 패러다임에 부합하는 또 한가지
전략은 바로 data augmentation 입니다.

01:04:48.928 --> 01:04:57.078
기본 버전의 학습과정에서는 데이터가 있고 레이블이 있고
이를 통해 매 스텝 CNN을 업데이트했습니다.

01:04:57.078 --> 01:05:03.555
하지만 그 대신 train time에 이미지를 무작위로 변환시켜 볼 수
있겠습니다. 레이블은 그대로 놔둔 채로 말입니다.

01:05:03.555 --> 01:05:09.418
이제 우리는 원본 이미지를 사용하는 것이 아니라
무작위로 변환시킨 이미지로 학습시키게 되는 것입니다.

01:05:09.418 --> 01:05:16.153
가령 이미지가 horizontal flips 할 수 있겠습니다.
이미지가 반전되도 고양이는 여전히 고양이죠

01:05:17.690 --> 01:05:23.763
혹은 이미지를 임의의 다양한 사이즈로 잘라서(crop)
사용할 수도 있습니다. 그래도 여전히 이미지는 고양이죠

01:05:25.188 --> 01:05:30.317
자 그럼 test time에서 stochasticity를 average out
시키는 것을 한번 생각해봅시다.

01:05:30.317 --> 01:05:34.309
"네개의 각 코너" 와 "중앙" 에서 잘라낸 이미지와
이들의 "반전 이미지"를 사용합니다.

01:05:34.309 --> 01:05:38.041
ImageNet 관련 모델들의 논문을 읽어보면 저자들이 보통
하나의 이미지를 그대로 사용했을 때의 성능과

01:05:38.041 --> 01:05:47.308
이미지 한장에서 10개를 잘라내서의 성능을 비교하곤 합니다.
*10개 = (4개코너 + 중앙) x (그냥 + 반전)

01:05:48.238 --> 01:05:56.345
Data augmentation으로 color jittering도 있습니다.
학습 시 이미지의 contrast 또는 brightness를 바꿔줍니다.

01:05:56.345 --> 01:06:04.642
color jittering에는 조금 더 복잡한 방법도 있습니다. PCA의
방향을 고려하여 color offset을 조절하는 방법입니다.

01:06:04.642 --> 01:06:11.456
이 방법은 color jittering을 좀 더 data-dependent한
방법으로 진행하는 것입니다. 자주 사용하는 방법은 아닙니다.

01:06:12.492 --> 01:06:18.037
일반적으로 data augmentation는 어떤 문제에도 적용해 볼 수 있는
아주 "일반적인 방법" 이라고 할 수 있습니다.

01:06:18.037 --> 01:06:24.940
어떤 문제를 풀려고 할 때, 이미지의 label을 바꾸지 않으면서
이미지를 변환시킬 수 있는 많은 방법들을 생각해 볼 수 있습니다.

01:06:24.940 --> 01:06:31.218
Train time에 입력 데이터에 임의의 변환을 시켜주게 되면
일종의 regularization 효과를 얻을 수 있습니다.

01:06:31.218 --> 01:06:38.954
그 이유를 다시 말씀드리면 train time에는 stochasticity가
추가되고 test time에는 marginalize out 되기 때문이죠

01:06:40.055 --> 01:06:45.232
지금까지 세 가지의 예시를 살펴보았습니다. dropout,
batch normalization, data augmentation 이죠

01:06:45.232 --> 01:06:47.154
하지만 또 다른 많은 방법들이 존재합니다.

01:06:47.154 --> 01:06:53.049
여러분들도 Regularization의 패턴을 잘 숙지하고 논문을 읽다보면
그런 방법들이 눈에 잘 들어올 것입니다.

01:06:53.049 --> 01:06:56.722
Dropout과 유사한 방법이 하나 더 있습니다.
DropConnect라는 방법이죠

01:06:56.722 --> 01:07:06.265
DropConnect은 activation이 아닌 weight matrix를
임의적으로 0으로 만들어주는 방법입니다.

01:07:06.265 --> 01:07:09.652
Dropout과 동작도 아주 비슷합니다.

01:07:09.652 --> 01:07:16.281
그리고 또 한가지 방법이 있습니다. 사람들이 자주 쓰지는 않지만
개인적으로 아주 좋은 아이디어라고 생각합니다.

01:07:16.281 --> 01:07:19.400
fractional max pooling 이라는 방법입니다.

01:07:19.400 --> 01:07:29.067
보통 2x2 maxpooling 연산은 고정된 2x2 지역에서 수행합니다.
하지만 fractional max pooling에서는 그렇게 하지 않고

01:07:29.067 --> 01:07:35.851
pooling연산을 수행 할 지역이 임의로 선정됩니다.

01:07:35.851 --> 01:07:43.070
여기 오른쪽 예시를 보시면 Train time에 샘플링될 수 있는
임의의 pooling region을 보실 수 있습니다.

01:07:43.070 --> 01:07:48.857
그리고 test time에 stochasticity를
average out 시키려면

01:07:48.857 --> 01:07:54.704
pooling regions를 고정시켜 버리거나 혹은 여러개의
pooling regions을 만들고 averaging over시킵니다.

01:07:54.704 --> 01:07:59.027
많이 사용하는 방법은 아니지만 참 좋은 아이디어입니다.

01:07:59.027 --> 01:08:05.890
Regularization pattern이라는 패러다임에서 봤을때 아주
놀랄만한 논문이 작년(2016)에 나왔습니다.

01:08:05.890 --> 01:08:09.911
올해 강의에 새롭게 소개시켜 드리는 논문입니다.
stochastic depth에 관련한 논문이죠

01:08:09.911 --> 01:08:15.490
왼쪽의 네트워크를 한번 보시죠 우리에게 아주
깊은 네트워크가 있다고 해봅시다.

01:08:15.490 --> 01:08:18.530
train time에 네크워크의 레이어를
randomly drop합니다.

01:08:18.530 --> 01:08:24.113
Train time에는 layer 중 일부를 제거해 버리고
일부만 사용해서 학습합니다.

01:08:24.114 --> 01:08:26.854
그리고 test time에는 전체 네트워크를 다 사용합니다.

01:08:26.854 --> 01:08:30.251
정말 놀라운 연구가 아닐 수 없습니다.

01:08:30.251 --> 01:08:35.310
하지만 이 방법의  regularization 효과는 dropout과 같은
다른 방법들과 유사합니다.

01:08:35.310 --> 01:08:42.041
그렇지만 아주 놀랍고 아주 최신의 연구이며(cutting-edge)
실제로 잘 사용하진 않지만 아주 좋은 아이디어입니다.

01:08:44.694 --> 01:08:52.673
regularization에 대해서 질문 있으신가요?

01:08:52.673 --> 01:08:57.046
[학생이 질문]

01:08:57.046 --> 01:09:01.184
질문은 보통 하나 이상의 regularization 방법을
사용하는지 입니다.

01:09:04.325 --> 01:09:09.751
일반적으로는  batch normalization를 많이 사용합니다.
대부분의 네트워크에서 보통 잘 동작하기 때문이죠

01:09:09.752 --> 01:09:12.650
아주 깊은 네트워크에서도 수렴을 잘 하도록 도와줍니다.

01:09:12.650 --> 01:09:25.204
대게는 BN만으로 충분합니다만 overfitting이 발생한다 싶으면
Dropout과 같은 다양한 방법을 추가해 볼 수 있습니다.

01:09:25.204 --> 01:09:28.526
보통은 이를 가지고 blind cross-validation
를 수행하지는 않습니다.

01:09:28.526 --> 01:09:33.942
대신에 네트워크에 overfit의 조짐이 보일때
하나씩 추가시켜 보는 것입니다.

01:09:36.400 --> 01:09:38.981
모델을 빠르게 학습시킬 수 있는 방법 중에는
transfer learning이 있습니다.

01:09:38.981 --> 01:09:47.018
지금까지는 regularization를 배웠습니다. 다양한 전략으로
train/test error간의 격차를 줄여보려는 것이었죠

01:09:48.903 --> 01:09:53.012
overfitting이 일어날 수 있는 상황중 하나는 바로
충분한 데이터가 없을 때 입니다.

01:09:53.012 --> 01:10:00.444
우리는 엄청 크고 파워풀한 모델을 원할지 모르겠지만 그 모델은
아주 작은 데이터셋을 지나치게 overfit할 수 있습니다.

01:10:00.444 --> 01:10:05.909
Regularization이 이를 해결할 수 있는 전략 중 하나입니다만
Transfer learning 이라는 방법도 있습니다.

01:10:05.909 --> 01:10:12.730
Transfer learning은 "CNN 학습에는 엄청많은 데이터가 필요함"
이라는 미신을 무너뜨려버립니다.

01:10:12.730 --> 01:10:15.300
아이디어는 정말 간단합니다.

01:10:15.300 --> 01:10:20.798
우선 여기 CNN모델이 있다고 해봅시다.
VGG스럽게 생긴 모델입니다.

01:10:20.798 --> 01:10:25.031
이 CNN을 가지고 우선은 ImageNet과 같은 아주 큰
데이터셋으로 학습을 한번 시킵니다.

01:10:25.031 --> 01:10:28.039
이정도 데이터셋이면 전체 네트워크를 학습시키기에
충분한 양입니다.

01:10:28.039 --> 01:10:34.596
자 이제 할 일은 Imagenet에서 학습된 features를
우리가 가진 작은 데이터셋에 적용하는 것입니다.

01:10:34.596 --> 01:10:42.864
이제는 1000개의 ImageNet 카테고리를 분류하는 것이 아니라
10종의 강아지를 분류하는 문제입니다. 데이터는 엄청 적습니다.

01:10:42.864 --> 01:10:45.917
이 작은 데이터셋은 C개의 클래스만 가지고있습니다.(10개)

01:10:45.917 --> 01:10:58.135
일반적인 절차는, 우선 가장 마지막의 FC Layer는 최종
feature와 class scores간의 연결인데 이를 초기화시킵니다.

01:10:59.651 --> 01:11:02.952
기존에 ImageNet을 학습시킬 때는
4,096 x 1,000 차원의 행렬이었습니다.

01:11:02.952 --> 01:11:09.182
하지만 우리의 새로운 문제를 풀기 위해서
4,096 x 10(C)으로 바꿔주게 됩니다.

01:11:09.182 --> 01:11:13.985
그리고 방금 정의한 가중치 행렬은 초기화시킵니다. 그다음
나머지 이전의 모든 레이어들의 가중치는 freeze시킵니다.

01:11:13.985 --> 01:11:21.947
그렇게 되면  linear classifier를 학습시키는 것과 같습니다.
오로지 마지막 레이어만 가지고 우리 데이터를 학습시키는 것입니다.

01:11:23.788 --> 01:11:28.756
이 방법은 사용하면 아주 작은 데이터셋일지라도
아주 작 동작하는 모델을 만들 수 있습니다.

01:11:28.756 --> 01:11:35.166
만일 데이터가 조금 더 있다면 전체 네트워크를
fine-tuning 할 수 있습니다.

01:11:35.166 --> 01:11:44.935
최종 레이어들을 학습시키고 나면, 네트워크의 일부만이 아닌
네트워크 전체의 학습을 고려해 볼 수도 있을 것입니다.

01:11:44.935 --> 01:11:49.434
데이터가 더 많이 있다면 네트워크의 더 많은 부분을
업데이트 시킬 수 있을지도 모릅니다.

01:11:49.434 --> 01:11:56.143
이 부분에서는 보통 기존의 Learning rate보다는 낮춰서 학습시킵니다.

01:11:56.143 --> 01:12:02.973
왜냐하면 기존의 가중치들이 이미 ImageNet으로 잘 학습되어 있고
이 가중치들이 대게는 아주 잘 동작하기 때문입니다.

01:12:02.973 --> 01:12:08.605
우리가 가진 데이터셋에서의 성능을 높히기 위해서라면
그 가중치들을 아주 조금씩만 수정하면 될 것입니다.

01:12:08.605 --> 01:12:15.490
따라서 transfer learning을 수행 함에 있어서 이렇게 생긴
2 x 2의 격자 시나리오를 예상해 볼 수 있을 것입니다.

01:12:15.490 --> 01:12:20.113
우선 아주 적은 양의 데이터셋이 있는 경우와
아주 많은 양의 데이터셋이 있는 경우가 있겠죠

01:12:21.188 --> 01:12:28.780
그리고 이전에 학습된 데이터셋과 현재 데이터셋이
얼마나 유사한지의 경우도 생각해 볼 수 있습니다.

01:12:28.780 --> 01:12:35.335
기존의 데이터와 유사한 경우라면 아주 순조로운 출발입니다.

01:12:35.335 --> 01:12:48.861
가령 현재의 데이터셋이 ImageNet와 유사하지만 소량의 경우라면,
기존 모델의 마지막 레이어만 학습시켜 볼 수 있겠습니다

01:12:48.861 --> 01:12:54.786
데이터가 그보다는 조금 많다고 생각이 되면
모델 전체를 fine tuning해 볼 수도 있을 것입니다.

01:12:54.786 --> 01:12:58.755
하지만 ImageNet과 다소 다르게 생긴 데이터셋을 가지고있다면
문제가 될 수 있습니다.

01:12:58.755 --> 01:13:06.781
가령 X-rays나 CAT scans와 같은 의료영상들은 대게
ImageNet의 데이터와는 많이 다릅니다.

01:13:06.781 --> 01:13:09.072
이 경우에는 좀 더 창의적인 방법이 필요할 수 있습니다.

01:13:09.072 --> 01:13:14.408
기존의 전략이 잘 동작할 수도 있겠지만 어쩌면 최종 레이어만
학습시키는 전략이 쓸모없어 질 수도 있을 것입니다.

01:13:14.408 --> 01:13:21.507
어쩌면 네트워크의 더 많은 부분은 다시 초기화시켜야 하거나 하는
더 창의적이고 경험적인 부분이 필요합니다.

01:13:21.507 --> 01:13:29.015
다만 이 문제는 여러분의 데이터셋이 아주 크다면 조금 완화됩니다.
이 경우에는 더 많은 레이어를 fine-tune 해 볼수 있기 때문이죠

01:13:29.015 --> 01:13:32.587
한가지 말씀드리고 싶은 것은
transfer learning이 아주 보편적이라는 것입니다.

01:13:32.587 --> 01:13:35.660
사실 transfer learning은 거의 일상적인 수준이 되었습니다.

01:13:35.660 --> 01:13:40.562
Computer vision 관련 논문들을 읽어보면 다양한 task에 대한
다음과 같은 시스템 다이어그램을 보실 수 있을 것입니다.

01:13:40.562 --> 01:13:44.706
왼쪽은 Object Detection과 관련된 다이어그램입니다.
오른쪽은 Image Captioning과 관련된 것이죠

01:13:44.706 --> 01:13:48.387
두 모델 모두 CNN구조를 가지고 있고
기본적으로 이미지를 처리합니다.

01:13:48.387 --> 01:13:53.913
요즘에는 거의 모든 computer vision 관련 응용 알고리즘들이
모델들을 밑바닥부터(from scrtch) 학습시키지 않습니다.

01:13:53.913 --> 01:13:59.973
대부분은 ImageNet pretrained-model을 사용하고 현재 본인의
task에 맞도록 fine tune 합니다.

01:13:59.973 --> 01:14:07.089
captioning의 경우 word vectors를
pretrain하기도 합니다.

01:14:07.089 --> 01:14:14.143
pretrained CNN 뿐만 아니라 규모가 큰 말뭉치로부터 학습된
pretrained word vectors도 함께 이용할 수 있겠습니다.

01:14:14.143 --> 01:14:22.278
captioning task에서는 pretrained word vectors을
사용하는 경우가 그닥 많지 않고 크게 중요하지 않습니다.

01:14:22.278 --> 01:14:33.225
여러분에게 어떤 문제가 있는데
이 문제에 대한 데이터셋이 크지 않은 경우라면

01:14:33.225 --> 01:14:41.673
우선 여러분의 task와 유사한 데이터셋으로 학습된
pretrained model 다운로드 받습니다.

01:14:41.673 --> 01:14:44.859
그리고 이 모델의 일부를 초기화시키고
여러분 데이터로 모델을 fine-tune 합니다.

01:14:44.859 --> 01:14:50.676
여러분의 Training data가 적당히만 있다면
아마 아주 잘 동작할 것입니다.

01:14:50.676 --> 01:14:57.738
이런 경우가 너무 흔하기 때문에 대부분의 딥러닝 소프트웨어
패키지들은 model zoo를 제공합니다.

01:14:57.738 --> 01:15:01.099
단지 접속만 하면 다양한 모델들의 pretrained 버전을
손쉽게 다운로드 받을 수 있습니다.

01:15:01.099 --> 01:15:06.043
오늘 한 내용을 요약해 보자면 우선 optimization을 배웠습니다.
training loss를 개선하는 방법이었죠.

01:15:06.043 --> 01:15:10.884
regularization에 대해서도 배웠습니다. test data에서의
성능을 향상시키는 방법이었습니다.

01:15:10.884 --> 01:15:12.838
Model ensembling도 regularization에 속했었죠

01:15:12.838 --> 01:15:17.440
그리고 transfer learning에 대해서도 배웠습니다.
데이터가 적을때 할 수 있는 아주 좋은 방법이었습니다.

01:15:17.440 --> 01:15:21.940
이들은 모두 아주 좋은 방법들입니다. 여러분들의 프로젝트 등에
사용해야만 하는 것들입니다.

01:15:21.940 --> 01:15:25.238
다음 시간에는 다양한 딥러닝 소프트웨어 패키지들이 대해서
조금 더 자세히 배워보도록 하겠습니다.